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.

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.

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.

When interacting with the API, please note that all numerical values, such as order amounts or timestamps, should be transmitted as strings. This ensures consistent data representation and prevents potential issues with floating-point precision.

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.

Accounts API

Retrieve portfolios

+ GET /platform/portfolios

This method allows to retrieve your portfolios (in UI terms - accounts).

Required API Key permissions: View

Properties

+ Response 200 OK (application/json)
  {
    "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": "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
isArchive Optional<Boolean> false (default value) - the requested account is active, true - the requested account is archived
portfolioTypes Optional<String> Filter the portfolios by type (see the PortfolioType variants below), may include multiple comma-separated types

Response

Field Data type Description
portfolios List<Portfolio> List of portfolios

Retrieve a portfolio by id

+ GET /platform/portfolios/{portfolioId}

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.

+ 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": {}
  }

Response

On success, the Portfolio is returned.

Retrieve wallets

+ GET /platform/wallets 

When you perform request without specifying any additional filters like portfolioId or currency, the method returns all wallets which has non-zero balances only.

Required API Key permissions: View

+ Response 200 OK (application/json)
  {
    "wallets": [
      {
        "walletId": "cleoe9air000u3b5o7m9f8npb",
        "portfolioId": "302fcb96-ec2b-4fff-88a5-2773cd77d112",
        "currency": "BTC",
        "mainCurrency": "BTC",
        "balance": "1.01480155",
        "stakeBalance": "0",
        "totalBalance": "1.01480155",
        "rebateBalance": "0",
        "reserve": "0.00014972",
        "locked": "0",
        "available": "1.01465183",
        "pledged": "0",
        "createdAt": "1677597540441",
        "createdBy": "75ed05af-ac02-4809-8891-e19ab395f59a",
        "updatedAt": "1677601972985",
        "accountId": "e23d0427-e312-4cd5-a1b3-cc32b7843ba8",
        "organizationId": "TESTORG",
        "portfolioType": "custody",
        "isActive": true
      },
      {
        "walletId": "7dd60ed7-eba0-4330-9249-15b14b8d9652",
        "portfolioId": "592d8ae70ecb39139",
        "currency": "USD",
        "balance": "885",
        "stakeBalance": "0",
        "totalBalance": "885",
        "rebateBalance": "0",
        "reserve": "14.00",
        "locked": "0",
        "available": "871.00",
        "physical": "885",
        "pledged": "0",
        "createdAt": "1658833481574",
        "createdBy": "4a2a3625-12ca-4cfc-9732-8c4951de73f9",
        "updatedAt": "1671201428375",
        "extra": {},
        "accountId": "e23d0427-e312-4cd5-a1b3-cc32b7843ba8",
        "organizationId": "SIDORENKOINC",
        "portfolioType": "trading-vault",
        "isActive": true
      }
    ]
  }

Request

The method request can include following parameters:

Parameter Data type Description
portfolioId Optional<String> Unique identifier of a portfolio
currency Optional<Currency> Filter wallets for a particular currency, may include multiple comma-separated currencies codes
mainCurrency Optional<Currency> Filter wallets for a particular main currency (chain), may include multiple comma-separated main currencies codes
nonEmpty Optional<Boolean> Filter only non zero wallets

Response

Field Data type Description
wallets List<Wallet> List of wallets

Retrieve a wallet by id

+ GET /platform/wallets/{walletId}

Required API Key permissions: View

Properties

+ Response 200 OK (application/json)
  {
    "walletId": "cleoe9air000u3b5o7m9f8npb",
    "portfolioId": "302fcb96-ec2b-4fff-88a5-2773cd77d112",
    "currency": "BTC",
    "mainCurrency": "BTC",
    "balance": "1.01480155",
    "stakeBalance": "0",
    "totalBalance": "1.01480155",
    "rebateBalance": "0",
    "reserve": "0.00014972",
    "locked": "0",
    "available": "1.01465183",
    "pledged": "0",
    "createdAt": "1677597540441",
    "createdBy": "75ed05af-ac02-4809-8891-e19ab395f59a",
    "updatedAt": "1677601972985",
    "accountId": "e23d0427-e312-4cd5-a1b3-cc32b7843ba8",
    "organizationId": "SIDORENKOINC",
    "portfolioType": "custody",
    "isActive": true
  }

Response

On success, the Wallet is returned.

Retrieve crypto addresses

+ GET /platform/crypto-addresses

This method allows to retrieve information about all crypto addresses in an organization's address book.

Required permissions: View

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'
    }
  ]
}

Response

Field Data type Description
cryptoAddresses List<CryptoAddresses>

Retrieve bank accounts

+ GET /platform/bank-accounts

This method allows to retrieve information about all fiat addresses in an organization's address book.

Required API Key permissions: View

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"
      }
    ]
  }

Response

Field Data type Description
bankAccounts List<BankAccount>

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
portfolioId 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

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
status Optional Set<OrderStatus> Filter by status

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.

Copper Network API

The Copper Network is a settlement network that enables counterparties to create and execute bilateral settlements while minimizing counterparty risk on the Copper Platform. Copper Network supports both crypto-to-crypto settlements and Fiat-linked settlements.

In addition to settlements between Copper Clients, the Copper Network also allows custodian-agnostic settlements through Copper Lite. This means that users can access the Copper Settlement network even if they are not registered as a Copper Custody Client.

The following settlement order types are currently supported by the Copper Network:

The status of active Copper Network Settlements and Transfers can be monitored and actioned for approval or cancellation from the order response.

Retrieve Copper Network participants

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

+ Response 200 OK:
{
    "counterparties": [
        {
          "counterpartyId": "7296511f-5940-4a91-a99d-79caaa48907f",
          "counterpartyName": "Copper Network",
          "networkTag": "copper",
          "counterpartyType": "standard",
          "tags": [
            "featured"
          ],
          "counterpartyDescription": "Copper Network Card",
          "_embedded": {
            "counterpartyDetails": {
              "counterpartyId": "92d06217-4daa-4c13-8484-af0173c60d5d",
              "counterpartyAddress": "Counterparty Address",
              "counterpartyPhoneNumber": "Counterparty Phone Number",
              "counterpartyEmail": "Counterparty Email"
            }
          }
        },
        {
          "counterpartyId": "92d06217-4daa-4c13-8484-af0173c60d5d",
          "counterpartyName": "Copper Network Connected Counterparty",
          "networkTag": "copper-connected",
          "counterpartyType": "standard",
          "tags": [
            "featured"
          ],
          "_embedded": {
            "counterpartyConnection": {
              "connectionId": "cde182baff1d3fe1e54f6e35baacc741",
              "requestorCounterpartyId": "bdbd7818-0b19-4e47-998d-0e268e9723d6",
              "receiverCounterpartyId": "92d06217-4daa-4c13-8484-af0173c60d5d",
              "requestStatus": "accepted"
            }
          }
        }
    ]

Retrieve the list of Copper Network Participants available for your organisation.

Required API Key permissions: Trading

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, networkTag or counterpartyDescription. This string can include minimum three characters.
isConnected Boolean Boolean value used to find only counterparties which accepted a network connection request

Response

Field Data type Description
counterparties Counterparties

Settle via Copper Network

Use the following methods to settle an order via Copper Network.

Get currencies and tokens supported for trading

+ GET /platform/currencies?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

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

Create a settlement order via Copper Network

+ POST /platform/orders

Required API Key permissions: Trading

Request

+ 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"
 }  

This request should include the following:

+ Response 201 (application/json)
  {
     "orderId": "35981617",
     "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",
     "status": "waiting-counterparty-approve",
     "orderType": "buy",
     "portfolioId": "46",
     ... 
   }
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 Trading amount
quoteAmount Optional<BigDecimal> Trading quote amount. Must be provided if priceLimit is missing
baseCurrency Currency Currency of the amount
quoteCurrency Currency Trading quote currency
mainCurrency Currency Currency defining a blockchain network for baseCurrency
quoteMainCurrency Currency Currency defining a blockchain network for quoteCurrency
limitType LimitType The limit type of the order. Acceptable otc
priceLimit Optional<BigDecimal> Price of a settle order. Must be provided if quoteAmount is missing
description Optional<String> Arbitrary description allowing to identify an order
deliveryType Optional<DeliveryType> Settlement order type. Use free-of-payment or payment-vs-payment (default)

Response

On success, the Order is returned. Includes deliveryType: free-of-payment or payment-vs-payment.

Accept an OTC order

+ PATCH /platform/orders/{counterpartyOrderId}

Required API Key permissions: Trading

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

+ Response 200 OK (application/json)

Use this method to accept an OTC order (from the counterparty side) 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

Use the following methods to transfer funds between Copper Network participants.

Create a one way transfer order via Copper Network

Transfers are one-way movements of funds between Copper Network participants.

+ POST /platform/orders

Required API Key permissions: Withdraw

Request

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

This request should include the CreateOrder model specific for trading:

+ Response 201 (application/json)
  {
     "orderId": "35981617",
     "externalOrderId": "F7FCCFD3-B61B-4467-B456-B0FC27CE4494",
     "status": "co-sign-require",
     "orderType": "withdraw",
     "portfolioId": "46",
     ...
   }
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 Amount of assets to be transferred
baseCurrency Currency Currency of the amount
mainCurrency Currency Currency defining a blockchain network for baseCurrency
description Optional<String> Arbitrary description allowing to identify an order.

Response

On success, the Order is returned.

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.

Transfer API

Create withdraw order

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

Note: from 24 January 2024, all outgoing withdrawal orders will need to include beneficiary information. Financial regulations require us to collect this information under the Travel Rule. There are two options to provide this information: you can either include it in the order creation request (see below) or use cryptoAddressId from the address book.

If there is no such address, it will be automatically created in the Address Book with given beneficiary data.

Example of withdraw order to external address (with travel rule data)

+ POST /platform/orders

+ 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",

    "beneficiaryType": "legal-person",
    "beneficiaryName": "Beneficiary name",
    "beneficiaryVaspId": "VASPUSNY",
    "beneficiaryVaspName": "Beneficiary VASP name"
  }

+ 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,

      "toCryptoAddress": {
        "cryptoAddressId": "cl5tgou1k000x3b5nb0f03ugv",
        "accountId": "d961e420-cbcf-4642-83fd-82b184828a1e",
        "organizationId": "NTESTORG",
        "currency": "BTC",
        "mainCurrency": "BTC",
        "name": "Autogenerated NTESTORG BTC",
        "address": "rwCQk17fhC8G9UCoMgaxsEQb6fVy8HhUY6",
        "createdBy": "cc1bafa6-eb87-4a1e-ae6d-d27d0ea921aa",
        "createdAt": "1658312909707",
        "isWhitelist": false,
        "travelRuleInfo": {
          "beneficiaryVerificationMethod": "vasp",
          "beneficiaryVerificationStatus": "verified",
          "beneficiaryName": "Some name",
          "beneficiaryType": "legal-person",
          "beneficiaryVaspId": "did:ethr:123456789",
          "beneficiaryVaspName": "VASP Name"
        }
      }
    },
    "createdBy": "cc1bafa6-eb87-4a1e-ae6d-d27d0ea921aa",
    "organizationId": "NTESTORG",
    "createdAt": "1572984084262",
    "updatedAt": "1572984084447"
  }

Request parameters

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). This value is mandatory for Custody, Trading or Settlement Lite portfolios.
toAddress Optional<String> Withdraw address.
toCryptoAddressId Optional<String> Withdraw crypto address identifier. To retrieve travel rule data from address book use cryptoAddressId value returned by Create address in address book method
toBankAccountId Optional<String> Withdraw bank account identifier
toPortfolioId Optional<String> Withdraw portfolioId identifier
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.

Note: The following fields are used to provide travel rules information when creating an order.

Field Data type Description
beneficiaryType BeneficiaryType Type of beneficiary: legal-person (default) or natural-person
beneficiaryName String Name of beneficiary receiving funds. The field may become mandatory in the future
beneficiaryVaspId Optional<String> The VASP ID associated with beneficiary address. To enable VASP verification VASP ID must be provided along with beneficiaryVaspName. If either parameter is missing, manual verification will be used
beneficiaryVaspName Optional<String> The VASP name associated with beneficiary address. To enable VASP verification VASP name must be provided along with beneficiaryVaspId. If either parameter is missing, manual verification will be used

Response

See Order.

Response inluder travelRuleInfo with the following travel rule fields:

Parameter Description
beneficiaryVerificationMethod Verification method: manual, signature or VASP
beneficiaryVerificationStatus Verification status: verified, unverified, unknown
beneficiaryType Type of beneficiary: legal-person (default) or natural-person
beneficiaryName Name of beneficiary receiving funds.
beneficiaryVaspId The VASP ID associated with beneficiary address.
beneficiaryVaspName The VASP name associated with beneficiary address.

Example: 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)
feeLevel <String> Note: required for specific currencies. Use if the response indicates a missing feeLevel field. Transaction processing fee: low, medium or high

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: View

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 OK (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<Currency> Filter by the order currency
orderType Optional<OrderType> 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 timestamp and sorted in ASC (oldest first)
createdSince Optional<String> Timestamp in milliseconds returning all orders created since a requested timestamp and sorted in DESC (newest first)
terminatedAtFrom Optional<Long> Timestamp in milliseconds returning all orders terminated since a requested timestamp (not sorted)
terminatedAtTo Optional<Long> Timestamp in milliseconds returning all orders terminated before a requested timestamp (not sorted)
portfolioType Optional<PortfolioType> 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.

Response

Field Data type Description
orders List<Order> List of orders

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 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<BlockchainTransactionType> Blockchain transaction type (see the description below). send is used by default

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

Get active stakes

+ GET /platform/staking/active-stakes

This method returns the list of the active stakes.

Method: GET

Required API Key permissions: View

Properties

+ Response 200 OK (application/json)
  {
    "activeStakes": [
      {
        "activeStakeId": "c563b5f83af3f6ba5f738c639c7a960e8dda9e6532f6208bd6ec628640d845c4",
        "portfolioId": "clk1bumcw000h3b6d7bzm16tg",
        "organizationId": "COMPANY",
        "depositTargetId": "3d070184-ce9c-404b-bb01-04a1c7c1d226",
        "currency": "ADA",
        "mainCurrency": "ADA",
        "activeStake": {
          "pool": {
            "poolId": "pool1k4nqdlvd9y3l4rfgj8fm80mcrrgcvgkx732x0n04jqfakxy2dvd",
            "poolName": "Cardano Pool"
          },
          "activeStakedAmount": "20038.58836",
          "claimableRewardsAmount": "46.947901",
          "rewardsRequireClaim": true,
          "readyToUnstake": false,
          "readyToRedelegate": true
        },
        "createdAt": "1692921790216",
        "updatedAt": "1694165767345",
        "isFromCopperPool": true
      }
    ],
    "_embedded": {
      "pendingCount": "0",
      "outstandingCount": "1"
    }
  }

Request

The request can have the following optional parameters:

Parameter Data type Description
currency Optional<Currency> Filter by the staked currency
mainCurrency Optional<Currency> Filter by the main currency for staking
portfolioId Optional<String> Return stakes only for specific portfolio
limit Optional<Integer> Limit output of the stake: 100 by default, max. 100
offset Optional<Integer> An offset between the beginning of the list and a first displayed element; 0 by default

Response

The response contains the list of active stakes. Each active stake includes the following fields:

Field Data type Description
activeStakeId String Unique identifier of the active stake
depositTargetId String Unique identifier of the Deposit Target
portfolioId String Unique identifier of the portfolio, for which the stake was created
organizationId Optional<String> Unique ID of the organisation
currency Currency Staked currency
mainCurrency Currency Main currency of the blockchain
createdAt Long Time of the stake creation
updatedAt Long Time of the latest stake update
activeStake ActiveStake Active stake data (see the description below)
ActiveStake
Field Data type Description
pool Optional<Pool> A pool that this stake is connected to (see the description below). Returned if the stake is connected to one pool
pools Optional<List<Pool>>> A list of pools that this stake is connected to. Returned if the stake is connected to two or more pools
claimableRewardsAmount Optional<BigDecimal> Amount of rewards, that can still be claimed from this active stake using TAKE_REWARD transaction
activeStakedAmount BigDecimal Amount which used to calculate rewards in the current epoch/period of stake
readyToUnstake Boolean true - the funds are ready to unstake, false - unstaking is currently impossible
readyToRedelegate Optional<Boolean> true - the active stake is ready to be redelegated, false - redelegating is currently impossible
rewardsRequireClaim Optional<Boolean> true - to claim rewards TAKE_REWARD transaction is required, false - TAKE_REWARD transaction is not required
rewardsAutoRestake Optional<Boolean> true - if rewards will be automatically restaked after payment false - rewards will not be restaked
requireChillToUnstake Optional<Boolean> Used for Substrate-based currencies: true - chill is required before unstaking BONDING stake, false - chill is not required
warning Optional<Warning> Warning message that notifies about a problem with this stake
stakeAddress Optional<String> Solana only: the address of a dedicated staking account
activeStakedAmount BigDecimal The amount of active stake
Pool
Field Data type Description
poolId String Pool identifier
poolName Optional<String> Pool name
totalBonded Optional<BigDecimal> Amount of all current stakes for the pool

Get pending stakes

+ GET /platform/staking/pending-stakes

This method returns the list of the pending stakes.

Method: GET

Required API Key permissions: View

Properties

+ Response 200 OK (application/json)
  {
    "pendingStakes": [
      {
        "pendingStakeId": "6e48b40e0ee61df2214569e4ac4f0b5d6682e8f0ffb4f3a56e9d0fd4d627bf23",
        "portfolioId": "clgeyi3vt000o3b6fap2dzjzy",
        "organizationId": "COMPANY",
        "depositTargetId": "11f39b64-c43e-4972-afe1-10070552110a",
        "currency": "ADA",
        "mainCurrency": "ADA",
        "pendingStake": {
          "pool": {
            "poolId": "pool1m8crhnqj5k2kyszf5j2scshupystyxc887zdfrpzh6ty6eun4fx",
            "poolName": "Cardano Pool"
          },
          "originPool": {
            "poolId": "pool1k4nqdlvd9y3l4rfgj8fm80mcrrgcvgkx732x0n04jqfakxy2dvd",
            "poolName": "Cardano Pool"
          },
          "pendingAmount": "1000",
          "pendingStakeStatus": "changing-validator",
          "pendingEndsAt": "1694217600000"
        },
        "createdAt": "1693469088208",
        "updatedAt": "1694185621606",
        "isFromCopperPool": false
      }
    ]
  }

Request

The request can have the following optional parameters:

Parameter Data type Description
currency Optional<Currency> Filter by the staked currency
mainCurrency Optional<Currency> Filter by the main currency for staking
portfolioId Optional<String> Return stakes only for specific portfolio
limit Optional<Integer> Limit output of the stakes: 100 by default, max. 100
offset Optional<Integer> An offset between the beginning of the list and a first displayed element; 0 by default

Response

The response contains the list of pending stakes. Each pending stake includes the following fields:

Field Data type Description
pendingStakeId String Unique identifier of the pending stake
depositTargetId String Unique identifier of the Deposit Target
portfolioId String Unique identifier of the portfolio, for which the stake was created
organizationId Optional<String> Unique ID of the organisation
currency Currency Staked currency
mainCurrency Currency Main currency of the blockchain
createdAt Long Time of stake creation
updatedAt Long Time of the latest stake update
pendingStake PendingStake Pending stake data (see the description below)
PendingStake
Field Data type Description
pool Optional<Pool> A pool that this stake is connected to (see the description below). Returned if the stake is connected to one pool
pools Optional<List<Pool>> A list of pools that this stake is connected to. Returned if the stake is connected to two or more pools
originPool Optional<Pool> If pendingStakeStatus is changing-validator: lists pools from which the stake was moved
pendingStakeStatus String The status of a pending stake (see description below)
pendingAmount BigDecimal Pending stake amount
canBeRebonded Optional<Boolean> Used for Substrate-based currencies:true - to rebond stake use REBOND_STAKE transaction during UNBONDING status, false - REBOND_STAKE transaction cannot be used
canBeUnstaked Optional<Boolean> Used for Substrate-based currencies: true - stake can be unbonded during BONDING status, false - rewards will not be restaked
requireChillToUnstake Optional<Boolean> Used for Substrate-based currencies: true - chill is required before unstaking BONDING stake, false - chill is not required
warning Optional<Warning> Warning message that notifies about a problem with this stake
stakeAddress Optional<String> Solana only: the address of a dedicated staking account

The pendingStakeStatus contains the following stake statuses:

Value Description
unbonding The stake is in waiting period before assets become available after unstaking
bonding The stake is in waiting period before it becomes active after initial staking
changing-validator The stake is in waiting period before it becomes active after changing validator

The pool is a JSON object that contains the following pool data:

Field Data type Description
poolId String Pool identifier
poolName Optional<String> Pool name
totalBonded Optional<BigDecimal> Amount of all current stakes for the pool

Get outstanding stakes

+ GET /platform/staking/outstanding-stakes

This method returns the list of the outstanding stakes.

Method: GET

Required API Key permissions: View

Properties

+ Response 200 OK (application/json)
  {
    "outstandingStakes": [
      {
        "outstandingStakeId": "1ea1be9ce75ca8e7c6fe0ebccc3940a74c55e7451fbc66e1af992ed9adcfe0e9",
        "portfolioId": "clk1bumcw000h3b6d7bzm16tg",
        "organizationId": "COMPANY",
        "depositTargetId": "3d070184-ce9c-404b-bb01-04a1c7c1d226",
        "currency": "ADA",
        "mainCurrency": "ADA",
        "outstandingOperation": {
          "outstandingAmount": "46.947901",
          "outstandingOperationType": "claim-reward"
        },
        "createdAt": "1691625675218",
        "updatedAt": "1694166801291",
        "isFromCopperPool": false
      }
    ]
  }  

Request

The request can have the following optional parameters:

Parameter Data type Description
currency Optional<Currency> Filter by the staked currency
mainCurrency Optional<Currency> Filter by the main currency for staking
portfolioId Optional<String> Return stakes only for specific portfolio
limit Optional<Integer> Limit output of the stakes: 100 by default, max. 100
offset Optional<Integer> An offset between the beginning of the list and a first displayed element; 0 by default

Response

The response contains the list of outstanding stakes. Each outstanding stake includes the following fields:

Field Data type Description
outstandingStakeId String Unique identifier of the outstanding stake
depositTargetId String Unique identifier of the Deposit Target
portfolioId String Unique identifier of the portfolio, for which the stake was created
organizationId Optional<String> Unique ID of the organisation
currency Currency Staked currency
mainCurrency Currency Main currency of the blockchain
createdAt Long Time of stake creation
updatedAt Long Time of the latest stake update
outstandingOperation outstandingOperation Outstanding stake data (see description below)

The outstandingOperation is a JSON object that contains the following stake data:

Field Data type Description
pool Optional<pool> A pool that this stake is connected to (see description below). Returned if the stake is connected to one pool
pools Optional <List<pool>> A list of pools that this stake is connected to. Returned if the stake is connected to two or more pools
outstandingOperationType String The type of the outstanding operation (see description below)
outstandingAmount BigDecimal Outstanding stake amount
stakeAddress Optional<String> Solana only: the address of a dedicated staking account. Can be used for unstaking operations
canCreatePool Optional<boolean> AVAX only: true - if outstandingOperationType is set to allocate-stake, false - outstandingOperationType is not set to allocate-stake

The outstandingOperationType contains the following outstanding operation types:

Value Description
claim-reward Outstanding reward, that should be claimed as separate blockchain transaction
complete-withdrawal Outstanding stake that was unstaked and requires separate blockchain transaction to make it available for regular operations
allocate-stake Outstanding stake that was staked and now requires allocation to a pool
complete-deposit Outstanding stake that was staked and requires separate blockchain transaction to make it active

The pool is a JSON object that contains the following pool data:

Field Data type Description
poolId String Pool identifier
poolName Optional<String> Pool name
totalBonded Optional<BigDecimal> Amount of all current stakes for the pool

ClearLoop API

The ClearLoop api contains information about ClearLoop: settlements, delegations/undelegations, exchanges information and any other relevant information related ClearLoop.

Fetch ClearLoop balances

+ GET /platform/clearloop/balances

Fetch all the ClearLoop balances, that could be add-funds (delegation) or remove-funds (undelegation) associated to your account.

Properties

+ Response 200 OK (application/json)

{
  "balances": [
        {
            "currency": "ETH",
            "balance": "9.85773100",
            "amount": "9.85773100",
            "available": "2.25",            
            "reserve": "0.00000000",
            "organizationId": "KLI1",
            "delegatedOrganizationId": "DRBT",
            "clientAccountId": "mNjMonVF",
            "portfolioId": "ckmnkyust000f3f5wpjk7rya4",
            "onChainSettlement": false,
            "_embedded": {
                "organizationName": "David"
            }
        }
   ]
}

Request

The method request can include following parameters:

Parameter Data type Description
portfolioId Optional<String> ClearLoop Copper portfolioId
organizationId Optional<String> Organization id to filter the results with.
includeEmptyWallets Boolean include or not empty wallets. Default value false

Response

The main field of the method response is "balances" including a list of Balances. The definition of balances can be find below.

Field Data type Description
balances List<ClearLoopBalance> List of ClearLoop Balances
ClearLoop Balance
Field Data type Description
organizationId String Unique Copper organization identifier
delegatedOrganizationId String Unique Copper exchange organization identifier
clientAccountId String Unique client exchange account identifier
portfolioId String Unique Copper client account identifier
currency String Currency that the balance is associated to
mainCurrency String Network
balance BigDecimal Total Balance value
amount BigDecimal Delegated Available Balance. Full amount delegated minus the reserved balance
available BigDecimal Available balance to undelegate. Minimum between funds on the exchange and delegated balance
reserve BigDecimal Reserved balance for open orders

Fetch ClearLoop actions

+ GET /platform/clearloop/actions

Fetch all the ClearLoop actions, that could be add-funds (delegation) or remove-funds (undelegation) associated to your account.

Properties

+ Response 200 OK (application/json)

{
    "actions": [
        {
            "delegatedOrganizationId": "GATE",
            "organizationId": "WGTEST",
            "orderId": "37952764",
            "clientAccountId": "110281676",
            "action": "add-funds",
            "currency": "BTC",
            "amount": "0.2",
            "createdAt": "1682367644707",
            "completedAt": "1682367727913",
            "usdAmount": "5473.973562629252",
            "status": "executed"
        },
        {
            "delegatedOrganizationId": "GATE",
            "organizationId": "WGTEST",
            "orderId": "36774083",
            "clientAccountId": "110281702",
            "action": "add-funds",
            "currency": "USDT",
            "amount": "1000",
            "createdAt": "1671627736258",
            "completedAt": "1671628377350",
            "usdAmount": "1000.0882673373988000",
            "status": "executed"
        }
    ],
    "pagination": {
      "pageSize": 100,
      "page": 1,
      "pages": 6,
      "totalItems": 550 
    } 
}

Request

The method request can include following parameters:

Parameter Data type Description
fromTimestamp Optional<String> Unix timestamp down to the millisecond granularity that can be used to retrieve records from this time
toTimestamp Optional<String> Unix timestamp down to the millisecond granularity that can be used to retrieve records until this time
clientAccountId Optional<String> Exchange account unique identifier for which records can be retrieved
portfolioId Optional<Int> Copper portfolio unique identifier for which records can be retrieved
actionType Optional<Long> 'add-funds' or 'remove-funds'
limit Optional<Integer> Number of records to return, maximum is 1000, default as 100 if parameter is absent
offset Optional<Integer> Number of records to skip over, default as 0 if parameter is absent
sortDirection Optional<String> Parameter to sort data in "asc" ascending or "desc" descending order according to "created_at", default as ascending if parameter is absent

Response

The main field of the method response is "actions" including a list of ClearLoopAction. The definition of actions can be find below.

Field Data type Description
actions List<ClearLoopAction> List of actions - Delegation and Undelegations
pagination Pagination Pagination object starting from page 1 until the last page N
ClearLoop Action
Field Data type Description
organizationId String Unique Copper organization identifier
delegatedOrganizationId String Unique Copper exchange organization identifier
clientAccountId String Unique client exchange account identifier
orderId Optional<String> Order identifier associated with this action.
action String 'add-funds' or 'remove-funds'
amount BigDecimal Decimal value amount.
currency String Currency
createdAt Long Unix timestamp at millisecond precision specific to the action creation time
completedAt Optional<Long> Unix timestamp at millisecond precision specific to the action completion time
usdAmount Optional<BigDecimal> USD amount value at the moment of the action
status String Order status: new, processing, executed and error
+ GET /platform/clearloop/actions/{actionId}

Fetch all the ClearLoop actions, that could be add-funds (delegation) or remove-funds (undelegation) associated to your account.

Properties

+ Response 200 OK (application/json)

{
  "delegatedOrganizationId": "GATE",
  "organizationId": "WGTEST",
  "orderId": "37952764",
  "clientAccountId": "110281676",
  "action": "add-funds",
  "currency": "BTC",
  "amount": "0.2",
  "createdAt": "1682367644707",
  "completedAt": "1682367727913",
  "usdAmount": "5473.973562629252",
  "status": "executed"
}

Request

The method request can include following parameters:

Parameter Data type Description
fromTimestamp Optional<String> Unix timestamp down to the millisecond granularity that can be used to retrieve records from this time
toTimestamp Optional<String> Unix timestamp down to the millisecond granularity that can be used to retrieve records until this time
clientAccountId Optional<String> Exchange account unique identifier for which records can be retrieved
portfolioId Optional<Int> Copper portfolio unique identifier for which records can be retrieved
actionType Optional<Long> 'add-funds' or 'remove-funds'

Response

The main field of the method response is "actions" including a list of ClearLoopAction. The definition of actions can be find below.

Field Data type Description
actions List<ClearLoopAction> List of actions - Delegation and Undelegations
pagination Pagination Pagination object starting from page 1 until the last page N
ClearLoop Action
Field Data type Description
organizationId String Unique Copper organization identifier
delegatedOrganizationId String Unique Copper exchange organization identifier
clientAccountId String Unique client exchange account identifier
orderId Optional<String> Order identifier associated with this action.
action String 'add-funds' or 'remove-funds'
amount BigDecimal Decimal value amount.
currency String Currency
createdAt Long Unix timestamp at millisecond precision specific to the action creation time
completedAt Optional<Long> Unix timestamp at millisecond precision specific to the action completion time
usdAmount Optional<BigDecimal> USD amount value at the moment of the action
status String Order status: new, processing, executed and error

Fetch ClearLoop settlements

+ GET /platform/clearloop/settlements

Fetch all the settlements between an organization and the different ClearLoop exchanges that the client has bound in their account.

Settlement is the process in which the balances between the exchange and Copper delegated balances are updated with the PnL over the last settlement cycle.

Required API Key permissions: ClearLoop Omni RiskOps Viewer

Make sure you have granted access to view ClearLoop Risk Analytics section: you will not be able to retrieve any information if your API key does not have this role assigned.

Properties

+ Response 200 OK (application/json)

{
  "settlements": [
    {
      "settlementId": "0752d9ac-79ca-4f95-9648-bbec101cd9ec",
      "settlementStatus": "failed",
      "cycleStartTimestamp": "1690257600000",
      "cycleEndTimestamp": "1690261200000",
      "deadline": "845129880000",
      "exchange": "Bitget",
      "exchangeId": "bitget",
      "createdAt": "1690257605149",
      "completedAt": "1690257605608",
      "failureReason": "An error happened.",
      "settlementDetails": [
        {
          "portfolioId": "cljyg0c6s000t3t6k7oqnyazc",
          "exchangeSettlementId": "db35b015-b530-402f-bf3e-32f8ca09d428",
          "clientAccountId": "51171",
          "settlementInstructions": []
        }
      ]
    },
    {
      "settlementId": "f261191e-0b6f-4b90-8d8c-82583f59fc94",
      "settlementStatus": "completed",
      "cycleStartTimestamp": "1690459403000",
      "cycleEndTimestamp": "1690545803000",
      "deadline": "1690718600000",
      "exchange": "Deribit",
      "exchangeId": "deribit",
      "createdAt": "1690462752465",
      "completedAt": "1690462752975",
      "settlementDetails": [
        {
          "portfolioId": "cljyg0c6s000t3t6k7oqnyazc",
          "exchangeSettlementId": "db35b015-b530-402f-bf3e-32f8ca09d428",
          "clientAccountId": "51171",
          "settlementInstructions": [
            {
              "currency": "USDC",
              "settlementAmount": "-29.48",
              "settlementAmountUSD": "29.483855459466098064",
              "orderId": "6325552",
              "orderStatus": "executed"
            },
            {
              "currency": "BTC",
              "settlementAmount": "0.001",
              "settlementAmountUSD": "29.47568121354447",
              "orderId": "6325550",
              "orderStatus": "executed"
            },
            {
              "currency": "ETH",
              "settlementAmount": "-0.006978",
              "settlementAmountUSD": "13.0897411038406200624",
              "orderId": "6325551",
              "orderStatus": "executed"
            }
          ]
        }
      ]
    }
  ],
  "pagination": {
    "pageSize": 100,
    "page": 1,
    "pages": 6,
    "totalItems": 550
  }
}

Request

The method request can include following parameters:

Parameter Data type Description
portfolioId Optional<String> Copper portfolio unique identifier for which records can be retrieved
clientAccountId Optional<String> Exchange account unique identifier for which records can be retrieved
exchange Optional<String> Exchange to query settlements associated with
cycles Optional<Int> Last number of cycles that you want to retrieve for every exchange. For example for 1 cycle, it would mean to bring back the last settlement for every exchange
cycleStartTimestamp Optional<Long> Unix timestamp down to the millisecond granularity that can be used to retrieve records for this cycle timestamp
fromMillis Optional<Long> Unix timestamp down to the millisecond granularity that can be used to retrieve records from this time
toMillis Optional<Long> Unix timestamp down to the millisecond granularity that can be used to retrieve records until this time
settlementStatusesNotIn Optional<String> Comma separated list with statuses not to be included: failed, pending-exchange-confirmation, new, completed
limit Optional<Integer> Number of records to return, maximum is 1000, default as 100 if parameter is absent
offset Optional<Integer> Number of records to skip over, default as 0 if parameter is absent
sortDirection Optional<String> Parameter to sort data in "asc" ascending or "desc" descending order according to "created_at", default as ascending if parameter is absent

Response

Field Data type Description
settlements List<ClearLoopSettlement> List of settlements
pagination Pagination Pagination object starting from page 1 until the last page N

The main field of the method response is "settlements" including a list of settlement. The definition of settlements can be find below.

+ GET /platform/clearloop/settlements/${settlementId}

Fetch one client settlement with a particular exchange account.

Required API Key permissions: ClearLoop Omni RiskOps Viewer

Make sure you have granted access to view ClearLoop Risk Analytics section: you will not be able to retrieve any information if your API key does not have this role assigned.

Properties

+ Response 200 OK (application/json)

{
  "settlementId": "f261191e-0b6f-4b90-8d8c-82583f59fc94",
  "settlementStatus": "completed",
  "cycleStartTimestamp": "1690459403000",
  "cycleEndTimestamp": "1690545803000",
  "deadline": "1690718600000",
  "exchange": "Deribit",
  "exchangeId": "deribit",
  "createdAt": "1690462752465",
  "completedAt": "1690462752975",
  "settlementDetails": [
    {
      "portfolioId": "cljyg0c6s000t3t6k7oqnyazc",
      "exchangeSettlementId": "db35b015-b530-402f-bf3e-32f8ca09d428",
      "clientAccountId": "51171",
      "settlementInstructions": [
        {
          "currency": "USDC",
          "settlementAmount": "-29.48",
          "settlementAmountUSD": "29.483855459466098064",
          "orderId": "6325552",
          "orderStatus": "executed"
        },
        {
          "currency": "BTC",
          "settlementAmount": "0.001",
          "settlementAmountUSD": "29.47568121354447",
          "orderId": "6325550",
          "orderStatus": "executed"
        },
        {
          "currency": "ETH",
          "settlementAmount": "-0.006978",
          "settlementAmountUSD": "13.0897411038406200624",
          "orderId": "6325551",
          "orderStatus": "executed"
        }
      ]
    }
  ]
}

Request

The method request needs a settlementId at the end of the URL endpoint.

Response

The 200 response contains all the field of a settlement defined below.

Common Settlement schemes

Settlement

Field Data type Description
settlementId String Unique Copper settlement identifier
exchangeId String Exchange id
cycleStartTimestamp Long Unix timestamp at millisecond precision specific to when the settlement cycle has started
cycleEndTimestamp Long Unix timestamp at millisecond precision specific to when the settlement cycle ends
deadline Long Unix timestamp at millisecond precision specific to the settlement deadline
settlementStatus SettlementStatus Status describing the settlement
createdAt Long Unix timestamp at millisecond precision specific to when the settlement started
completedAt Optional <Long> Unix timestamp at millisecond precision specific to when the settlement was fully completed
failureReason Optional <String> Reason why the settlement has not been completed successfully

Settlement Details

Field Data type Description
portfolioId String Unique Copper account identifier
clientAccountId String Unique exchange account identifier
exchangeSettlementId Optional <String> Exchange unique identifier of settlement
settlementInstructions List <SettlementInstruction> List of all settlement instructions

Settlement Instruction

Field Data type Description
currency String Settlement currency
settlementAmount BigDecimal PnL of the client in the settlement period. This amount is the aggregation between mainAccount and subaccounts in the exchange
settlementAmountUSD BigDecimal Same as the settlementAmount but calculated in USD
balance BigDecimal Client Delegated Balance in Copper fetched at the moment of the settlement
orderId Optional <String> Order id associated to the settlement
OrderStatus Optional<OrderStatus> Describes the order status

Settlement Status

Status Description
new newly created settlement with only metadata information
in-progress settlement is ready to be started or has already started. We have received succcessfully settlement instructions from exchange
completed settlement completed successfully
failed settlement failed after having retried it until the end of the cycle. This is due to errors in the api call to exchange that after many retries during the cycle couldn't be recovered
partially-completed some settlement instructions has been completed and other are still in progress. This is due to client trading vault orders missing signatures
pending-exchange-confirmation pending exchange to send the settlement instructions. This is due to some api/network error connecting to the exchange
pending-previous-settlement waiting for a previous settlement to be completed

Fetch ClearLoop exchanges

+ GET /platform/clearloop/exchanges

Fetch all ClearLoop exchanges information related collateral health and settlements configuration

Required API Key permissions: ClearLoop Omni RiskOps Viewer

Make sure you have granted access to view ClearLoop Risk Analytics section: you will not be able to retrieve any information if your API key does not have this role assigned.

Properties

+ Response 200 OK (application/json)

{
  "clearLoopExchanges": [
    {
      "exchangeId": "okex",
      "name": "OKX",
      "settlementDetails": {
        "frequency": "14400000",
        "nextSettlementTimestamp": "1694419200000"
      },
      "collateralDetails": {
        "currencies": []
      }
    },
    {
      "exchangeId": "deribit",
      "name": "Deribit",
      "settlementDetails": {
        "frequency": "86400000",
        "nextSettlementTimestamp": "1694421000000"
      },
      "collateralDetails": {
        "currencies": []
      }
    }
  ]
}

Request

The method request does not need any parameter.

Response

The main field of the method response is "exchanges" including a list of ClearLoop exchanges. The definition of exchanges could be find below.

+ GET /platform/clearloop/exchanges/${exchangeId}

Fetch one ClearLoop exchange.

Required API Key permissions: ClearLoop Omni RiskOps Viewer

Make sure you have granted access to view ClearLoop Risk Analytics section: you will not be able to retrieve any information if your API key does not have this role assigned.

Properties

+ Response 200 OK (application/json)

{
  "exchangeId": "deribit",
  "name": "Deribit",
  "settlementDetails": {
    "frequency": "86400000",
    "nextSettlementTimestamp": "1694421000000"
  },
  "collateralDetails": {
    "currencies": []
  }
}

Request

The method request needs a exchangeId at the end of the URL endpoint.

Response

The 200 response contains all the fields of a ClearLoop exchange defined below.

Common ClearLoop Exchange schemes

Exchange

Field Data type Description
exchangeId String Unique Copper exchange identifier
name String Exchange name
settlementDetails ExchangeSettlementDetails Settlements configuration details
collateralDetails ExchangeCollateralDetails Collateral details

ExchangeSettlementDetails

Field Data type Description
frequency Integer Frequency of the settlement in milliseconds
nextSettlementTimestamp Integer Unix timestamp at millisecond precision specific when the next settlement cycle will start

ExchangeCollateralDetails

Field Data type Description
currencies Array<ClearLoopCurrencyCollateralDetails> Collateral details per currency

ClearLoopCurrencyCollateralDetails

Field Data type Description
settlementCurrency String Settlement currency
uPnL BigDecimal Unrealised PnL, sourced for open positions on Derivative
currentCollateralBalance BigDecimal Current Exchange collateral balance in their ClearLoop accou
uPnLExcessDeficit BigDecimal Difference between the current collateral balance and unrealised PnL
buffer BigDecimal Ratio of current collateral excess/deficit over the current collateral balance. Displayed as %
updatedAt ExchangeCollateralDetails Timestamp in milliseconds, reflecting the latest time that data was computed/fetched

Fetch ClearLoop Margin Calls

+ GET /platform/clearloop/margin-calls

Fetch all ClearLoop exchanges margin calls. A margin call happens when settlements are stuck during more than one settlement cycle due to insufficient funds in the exchange Copper account.

Required API Key permissions: ClearLoop Omni RiskOps Viewer

Make sure you have granted access to view ClearLoop Risk Analytics section: you will not be able to retrieve any information if your API key does not have this role assigned.

Properties

+ Response 200 OK (application/json)

{
  "marginCalls": [
    {
      "id": "351",
      "issuedBy": "J DOE",
      "exchange": "unicorn",
      "recipients": "risk@copper.co",
      "marginCallIssuanceTimestamp": "1686678000000",
      "issueVia": "EMAIL",
      "settlementCycleTimestamp": "1686672000000",
      "asset": "BNB",
      "networkChain": "BNB",
      "marginCallAmountCoin": "232",
      "marginCallAmountUsd": "2222",
      "totalSettlementAmountCoin": "412",
      "totalSettlementAmountUsd": "98435",
      "followUpVia": "SLACK",
      "followUpLogs": "https://coppertech-external.slack.com/archives/C0543TGKKED/p1686674608846589,",
      "acknowledgmentReceipt": false,
      "settlementCompletionTimestamp": "1686677340000",
      "comments": "comments",
      "default": false
    }
  ],
  "pagination": {
    "pageSize": 100,
    "page": 1,
    "pages": 6,
    "totalItems": 550
  }
}

Request

The method request can include following parameters:

Parameter Data type Description
fromMillis Optional<Long> Unix timestamp down to the millisecond granularity that can be used to retrieve records from this time
toMillis Optional<Long> Unix timestamp down to the millisecond granularity that can be used to retrieve records until this time
limit Optional<Integer> Number of records to return, maximum is 1000, default as 100 if parameter is absent
offset Optional<Integer> Number of records to skip over, default as 0 if parameter is absent
sortDirection Optional<String> Parameter to sort data in "asc" ascending or "desc" descending order according to "margin_call_issuance_timestamp", default as ascending if parameter is absent

Response

Field Data type Description
marginCalls List<ClearLoopMarginCall> List of ClearLoop Margin Calls
pagination Pagination Pagination object starting from page 1 until the last page N

The main field of the method response is "marginCalls" including a list of ClearLoop margin calls. The definition of a margin call can be find below.

+ GET /platform/clearloop/margin-calls/${marginCallId}

Fetch one ClearLoop exchange.

Required API Key permissions: ClearLoop Omni RiskOps Viewer

Make sure you have granted access to view ClearLoop Risk Analytics section: you will not be able to retrieve any information if your API key does not have this role assigned.

Properties

+ Response 200 OK (application/json)

{
  "id": "351",
  "issuedBy": "J DOE",
  "exchange": "unicorn",
  "recipients": "risk@copper.co",
  "marginCallIssuanceTimestamp": "1686678000000",
  "issueVia": "EMAIL",
  "settlementCycleTimestamp": "1686672000000",
  "asset": "BNB",
  "networkChain": "BNB",
  "marginCallAmountCoin": "232",
  "marginCallAmountUsd": "2222",
  "totalSettlementAmountCoin": "412",
  "totalSettlementAmountUsd": "98435",
  "followUpVia": "SLACK",
  "followUpLogs": "https://coppertech-external.slack.com/archives/C0543TGKKED/p1686674608846589,",
  "acknowledgmentReceipt": false,
  "settlementCompletionTimestamp": "1686677340000",
  "comments": "comments",
  "default": false
}

Request

The method request needs a marginCallId at the end of the URL endpoint.

Response

The 200 response contains all the fields of a Margin Call defined below.

Common ClearLoop Margin Call schemes

ClearLoop Margin Call

Field Data type Description
id Integer Unique Copper Exchange Identifier.
issuedBy String Copper employee that issues the margin call to the exchange.
exchange String Exchange ID.
recipients String Coma separated list of email addresses for the margin call recipients.
marginCallIssuanceTimestamp Long Unix Timestamp in ms recording the date and time that a margin call is issued.
issueVia String Approved channel used to officially issue the margin call. Currently, only EMAIL is an approved channel.
settlementCycleTimestamp Long Unix Timestamp in ms recording the date and time that a settlement cycle ends with collateral shortfall, resulting in a margin call issuance.
asset String Asset/Settlement Currency on which the exchange has collateral shortfall and additional funds are needed to cover the settlement amounts.
networkChain String Approved chain on which funds can be deposited in/withdrawn from the ClearLoop Omnibus account.
marginCallAmountCoin BigDecimal Collateral shortfall amount on asset value (number of tokens). The exchange needs to deposit this amount to cover all settlement obligations.
marginCallAmountUsd BigDecimal Collateral shortfall amount on USD equivalent value. The exchange needs to deposit this amount to cover all settlement obligations.
totalSettlementAmountCoin BigDecimal The total settlement amount on asset value (number of tokens) that the exchange needs to deliver to ClearLoop clients.
totalSettlementAmountUsd BigDecimal The total settlement amount on USD equivalent value that the exchange needs to deliver to ClearLoop clients.
settlementCompletionTimestamp Long Unix Timestamp in ms recording the date and time that settlements are completed. This happens as soon as the exchange transfers the required shortfall amount.
isDefault Boolean If an Exchange does not meet the settlement obligations within the contractually agreed time period, there is an event of default.
isDefaultComments String Commentary explaining the reason if Copper does not act on the event of default,i.e., does not default the exchange.

Fetch ClearLoop Treasury Holdings

+ GET /platform/clearloop/holdings

Fetch ClearLoop treasury holdings information. Returns the Copper ClearLoop treasury details per currency vs Copper ClearLoop client aggregated balances.

Required API Key permissions: ClearLoop Omni RiskOps Viewer

Make sure you have granted access to view ClearLoop Risk Analytics section: you will not be able to retrieve any information if your API key does not have this role assigned.

Properties

+ Response 200 OK (application/json)

{
  "holdings": [
    {
      "asset": "USDC",
      "variance": "-7165.59345678",
      "clearLoopOnChainReserve": "1",
      "clearLoopVirtualBalance": "7166.59345678",
      "clientBalance": "982.52654322",
      "depositAddresses": [
        {
          "network": "TRX",
          "depositAddresses": [
            "TEzh31h7xk1Xu7TNzQGG7kKLmsii"
          ]
        },
        {
          "network": "BSC",
          "depositAddresses": [
            "0xa10a1af58c99a8sssssssssssssss"
          ]
        },
        {
          "network": "ETH",
          "depositAddresses": [
            "0x761c0d34193c23ad01a738aa1b",
            "0x3d134293effa3623fb96fc8827ff0ef"
          ]
        }
      ]
    }
  ]
}

Request

The method request can include following parameters:

Parameter Data type Description
asset Optional<String> Currency or asset

Response

The main field of the method response is "holdings" including a list of ClearLoop treasury holdings.

ClearLoop Treasury Holding

Field Data type Description
asset String Currency or asset
variance String Difference between treasury blockchain balance and clients aggregated balance
clearLoopOnChainReserve String Treasury blockchain amount
clearLoopVirtualBalance String Aggregated clients balance
clientBalance Long Balance associated with the client that made the request
depositAddresses List<DepositAddress> List of deposit addresses per network

ClearLoop Treasury Deposit Address

Field Data type Description
network String Currency Network
depositAddresses List<String> List of deposit addresses

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 canceled
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.
pricingSource Optional<Pricing Source> The source for where the prices come which keep the LTV up to date. Defaults to external.
lenderOrganizationId String The organization id of the lender.
borrowerOrganizationId String The organization id of the borrower.
terms Terms The terms of the loan.

Response

See Loan

Cancel

+ 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 lender to cancel the loan before it has been disbursed.

Write Off

+ PATCH /loans/{loanId}

+ Headers
  Content-Type: application/vnd.write-off+json

+ Request
  {
  }

+ Response 200 OK

Required API Key permissions: Lending or Lending Arranger

This allows a lender to write off a loan in open, margin call, defaulting or repaying.

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.

Cancel Default

+ PATCH /loans/{loanId}

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

+ Request
  {
  }

+ Response 200 OK

Required API Key permissions: Lending or Lending Arranger

This allows a lender to cancel 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.
pricingSource Optional<Pricing Source> The source for where the prices come which keep the LTV up to date. Defaults to external.

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

Pricing Source

The pricing source identifies where the prices come from that are used to keep the ltv up to date.

Name Description
external They are provided by an external partner using the valuations api.
copper Copper uses its internal pricing providers to update the ltv on an hourly basis.

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 canceled.

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. There is an option to pass APP_PORT environmental variable to specify a port within the container.
    • 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 starting 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,
        "depositTargetId": "532443055",
        "transactionType": "send",
        "version": "0",
        "transactionRequest": {
          "fee": "231000000000000",
          "transactionType": "send",
          "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,
      "depositTargetId": "532443055",
      "transactionType": "send",
      "version": "0",
      "transactionRequest": {
        "fee": "231000000000000",
        "transactionType": "send",
        "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

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: ""                       # Your Master password
        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.

Fees Vaults

Fees vaults are a type of MPC vault that are used to pay fees for token transfers from proxy wallets to the destination accounts.

In order to sign and broadcast the required transactions, a dockerised application made by Copper is provided to process transactions along with 'Copper Unlimited Online'.

When orders are created by the Copper platform to pay fees for token transfers from proxy wallets, the dockerised application will them sign using 'Copper Unlimited Online' and broadcast the transactions to the blockchain automatically.

Note: if you want to use your own fees wallets to pay fees, contact your account manager to set up a specific fees wallet account in your organisation.

Software requirements

In order to operate the dockerised application, an instance of 'Copper Unlimited Online' must be configured with the required wallet shards for the associated fees vault.

The fees vault service is provided as a Docker image based on node:lts-alpine and can be run using Docker Compose.

The image is publicly available in Copper DockerHub.

Network characteristics of the image:

How to launch

Wallet configuration

Before launching, a wallet configuration file must be created. This is a JavaScript file containing a JSON object that describes the wallets that the application can sign transactions for. The file is in the following format:

module.exports = [
  {
    portfolioId: '<fees vault account ID>',
    currency: 'ETH',
    walletFilename: 'eth-wallet.copper',
    walletPassword: process.env.ETH_WALLET_PASSWORD,
  },
  {
    portfolioId: '<fees vault account ID>',
    currency: 'TRX',
    walletFilename: 'trx-wallet.copper',
    walletPassword: process.env.TRX_WALLET_PASSWORD,
  },
];

Any number of wallets can be configured in this file, but each wallet must have the following properties:

Launching the application

  1. Configure and run the Copper Unlimited Online instance with shards for the configured MPC wallets in your organization's fees vault
  2. Start the dockerised CU Online. Before running, specify following fields:
    • a path to your folder with the *.copper file.
    • 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.
    • the URL of the CU Online instance.
    • the API key and secret that the application will use to connect to the Copper API.
    • the withdrawal password of the organization that the application will use to authenticate for withdrawals.
    • Any other environment variables used in the wallet configuration file. (e.g. wallet passwords)

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}/wallets-config.js:/app/wallets-config.js \
  -e APP_ENVIRONMENT='testnet' \
  -e APP_CUSTODY_DOCKER_URL='<URL of CU Online>:3010' \
  -e APP_API_KEY='<API key>' \
  -e APP_API_SECRET='<API secret>' \
  -e APP_WITHDRAWAL_PASSWORD='<withdrwal password>' \
  copperexchange/hot-wallet:latest

# ${PWD}/wallets-config.js is the wallet config file described above.
# The APP_ENVIRONMENT variable can be 'testnet', 'stage' or 'mainnet' (see details above).
# The APP_CUSTODY_DOCKER_URL variable is the URL of the CU Online instance that the application will connect to.
# The APP_API_KEY and APP_API_SECRET variables are the API key and secret that the application will use to connect to the Copper API.
# The APP_WITHDRAWAL_PASSWORD variable is the withdrawal password of the organization that the application will use to authenticate for withdrawals.

After starting the server, it should now be possible to send token transfers from proxy addresses paying the fees from the fees vault account. In this flow, orders will be created automatically to cover the fees amounts and the dockerised application will sign and broadcast the transactions to the blockchain.

Activity API

Get information about the organisation account activity.

Retrieve activities

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

Required API Key permission: view

Make sure you have granted access to the user: you will not be able to retrieve an organizations activities if the user tied to the API key does not have assigned permissions.

Properties

+ Response 200 OK 
  {
    "activities": [
      {
        "activityId": "",
        "name": "",
        "description": "",
        "userId": "",
        "organizationId": "",
        "portfolioId": "",
        "correlationId": ""
        "createdAt": "",
        "extra": {
          "externalId": "",
          "roles":[]
        }
    ],
  }

Request

The method request can include following parameters:

Parameter Data type Description
search Optional<String> String used to find one or more activities according to their description. This string can include minimum three characters.
createdBy Optional<String> User ID of the activity creator
createdFrom Optional<Long> Timestamp from when to return activities
createdTo Optional<Long> Timestamp to when to return activities
limit Optional<Integer> Number of records to return, default as 100 if parameter is absent
offset Optional<Integer> Number of records to skip over, default as 0 if parameter is absent

Response

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

Field Data type Description
activityId String Unique identifier of the activity
name String Name of the activity
description String Description of the activity
userId String Unique user identifier
organizationId String Unique organization identifier
createdAt Long Timestamp of activity creation
extra ActivityExtra Extra activity data(see the ActivityExtra below)

ActivityExtra

Parameter Data type Description
externalId Optional<String> Unique external identifier
roles Optional<String> List roles of team member

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
clearloop-delegation-created ClearLoop delegation created
clearloop-delegation-completed ClearLoop delegation completed
clearloop-delegation-failed ClearLoop delegation failed
clearloop-undelegation-created ClearLoop undelegation created
clearloop-undelegation-completed ClearLoop undelegation completed
clearloop-undelegation-failed ClearLoop undelegation failed

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"
    ]
}

Address book

Manage wallet addresses and whitelisting for safe and easy transfers.

Create crypto address

This method adds a crypto address to the address book in the External tab.

+ POST /platform/crypto-addresses

+ Request
  {
    "cryptoAddressId": "cl5tgou1k000x3b5nb0f03ugv",
    "accountId": "8A85A7E8-B56D-4B20-A098-900911759E85",
    "currency": "BTC",
    "mainCurrency": "BTC",
    "name": "Crypto Address Name",
    "address": "hsdf892q4asdkgq20adfkhgq2987sdfjkasdfasdf",
    "beneficiaryName": "Some name",
    "beneficiaryType": "legal-person",
    "beneficiaryVaspId": "did:ethr:123456789",
    "beneficiaryVaspName": "VASP Name"
  }

+ Response 201 Created (application/json)
  {
    "cryptoAddressId": "cl5tgou1k000x3b5nb0f03ugv",
    "accountId": "8A85A7E8-B56D-4B20-A098-900911759E85",
    "organizationId": "NTESTORG",
    "currency": "BTC",
    "mainCurrency": "BTC",
    "name": "Crypto Address Name",
    "address": "hsdf892q4asdkgq20adfkhgq2987sdfjkasdfasdf",
    "createdBy": "uuid",
    "updatedBy": "uuid",
    "createdAt": "1658312909707",
    "isWhitelist": false,
    "travelRuleInfo": {
      "beneficiaryVerificationMethod": "vasp",
      "beneficiaryVerificationStatus": "verified",
      "beneficiaryName": "Some name",
      "beneficiaryType": "legal-person",
      "beneficiaryVaspId": "did:ethr:123456789",
      "beneficiaryVaspName": "VASP Name"
    }
  }

Request

Parameter Data type Description
cryptoAddressId <String> Unique crypto address identifier. Maximum size is 64
accountId <String> Unique account identifier.
organizationId Optional <String> Unique organization identifier.
createdBy <String> User ID of the crypto address creator
portfolioIds Optional <Set<String>> Filter entries by a number of portfolio identifiers
currency <Currency> Crypto address currency. Maximum size is 10
mainCurrency Optional <Currency> Currency of main blockchain of the vault (e.g. For USDT, it could be either ETH or BTC). Maximum size is 10
address <String> Address string
name <String> Name of the crypto address
memo Optional <String> Address memo
acceptTokens Optional<Boolean> null(default value), true - allow ERC20 token withdrawals to this address. It works only for ETH currency
isWhitelist Optional <String> false (default value) - the crypto address isn't whiteListed, true - the crypto address is whiteListed

Note: The following fields are used to provide travel rules information when creating an address. Travel rules for withdrawal orders are currently under construction. Using following parameters may not be reliable.

Field Data type Description
beneficiaryType BeneficiaryType Type of beneficiary: legal-person (default) or natural-person
beneficiaryName String Name of beneficiary receiving funds. The field may become mandatory in the future
beneficiaryVaspId Optional<String> The VASP ID associated with beneficiary address. To enable VASP verification VASP ID must be provided along with beneficiaryVaspName. If either parameter is missing, manual verification will be used
beneficiaryVaspName Optional<String> The VASP name associated with beneficiary address. To enable VASP verification VASP name must be provided along with beneficiaryVaspId. If either parameter is missing, manual verification will be used

Response

Parameter Data type Description
cryptoAddressId <String> Unique crypto address identifier. Maximum size is 64
accountId <String> Unique account identifier. Maximum size is 64
organizationId Optional <String> Unique organization identifier.
portfolioIds Optional <Set<String>> Filter entries by a number of portfolio identifiers
currency <Currency> Crypto address currency. Maximum size is 10
mainCurrency Optional <Currency> Currency of main blockchain of the vault (e.g. For USDT, it could be either ETH or BTC). Maximum size is 10
name <String> Name of the crypto address
address <String> Address string
destinationTag Optional <Long> Destination tag (for XRP addresses)
memo Optional <String> Address memo
acceptTokens Optional<Boolean> Flag allows ERC20 token withdrawals to this address. It works only for ETH currency
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
lastUsedAt Optional <Long> Time of last usage of the crypto address
isWhitelist Optional <String> false (default value) - the crypto address isn't whiteListed, true - the crypto address is whiteListed
travelRuleInfo Optional<travelRuleInfo> Information about beneficiaries (see below)

travelRuleInfo contains the following fields:

Parameter Description
beneficiaryVerificationMethod Verification method: manual, signature or VASP
beneficiaryVerificationStatus Verification status
beneficiaryType Type of beneficiary: legal-person (default) or natural-person
beneficiaryName Name of beneficiary receiving funds.
beneficiaryVaspId The VASP ID associated with beneficiary address.
beneficiaryVaspName The VASP name associated with beneficiary address.

Get crypto address

+ GET /platform/crypto-addresses/{cryptoAddressId}

+ Response 200 (application/json)
  {
    "cryptoAddressId": "cl5tgou1k000x3b5nb0f03ugv",
    "accountId": "uuid",
    "organizationId": "NTESTORG",
    "currency": "BTC",
    "mainCurrency": "BTC",
    "name": "Crypto Address Name",
    "address": "hsdf892q4asdkgq20adfkhgq2987sdfjkasdfasdf",
    "memo": "45",
    "createdBy": "uuid",
    "updatedBy": "uuid",
    "createdAt": "1658312909707",
    "lastUsedAt": "1606237167221",
    "isWhitelist": true,
    "travelRuleInfo": {
      "beneficiaryVerificationMethod": "vasp",
      "beneficiaryVerificationStatus": "verified",
      "beneficiaryName": "Some name",
      "beneficiaryType": "legal-person",
      "beneficiaryVaspId": "did:ethr:123456789",
      "beneficiaryVaspName": "VASP Name"
    }
  }

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 ClearLoop account
  "toPortfolioId": "Bahng9nai9ieGhaeg8Heasokahshee7A"  # To the parent Trading 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.

The response contains the following information about the funds:

Field Data type Description
balance BigDecimal Total amount of currency
locked BigDecimal Delegated amount of currency, including the funds delegated to the ClearLoop sub accounts
available BigDecimal Unused funds
reserve BigDecimal The amount of funds reserved for all active orders
totalBalance BigDecimal A sum of balance and stakeBalance for all portfolios.
stakeBalance BigDecimal The balance of funds that are locked in staking. Applies only for portfolios with custody and trading-vault types(#portfolio-types)

The following formula shows how the balance is calculated:

balance = available + reserve + locked

If you query a ClearLoop portfolio for its balance then keep in mind the following:

If you query the trading portfolio (or trading-vault) that has a clearloop portfolio underneath it then keep in mind the following details:

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

+ Response 200 OK
{
  "wallets": [
    {
        "walletId": "cl122gxq1000h386585dgi2vw",
        "portfolioId": "ulCJwlxHCV0VOZoZGrLJkYT1",
        "currency": "ETH",
        "mainCurrency": "BSC",
        "balance": "0.000202725",
        "stakeBalance": "0",
        "totalBalance": "0.000202725",
        "reserve": "0.000000000",
        "locked": "0.0001012",
        "available": "0.000101525",
        "pledged": "0",
        "createdAt": "1647949309870",
        "createdBy": "6cba908a-763b-49b9-bdf9-4559ec28e738",
        "updatedAt": "1660811782426",
        "extra": {
            "walletShardUploadedBy": "admin"
        },
        "accountId": "29af7ea0-5878-4a6a-93de-6647e0d287fa",
        "organizationId": "1234567",
        "portfolioType": "custody",
        "_embedded": {
            "depositTargets": [
                {
                    "targetType": "crypto",
                    "depositTargetId": "69c7192d-d745-4f91-b762-7eb850a5e49f",
                    "mainCurrency": "BSC",
                    "address": "0xc7eed7ddf7c17a11d34fe067d186bc873ae271d7",
                    "status": "enabled"
                }
            ],
            "pendingDepositTargets": []
        },
        "isActive": true
    }
 ]
}

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 OrderStatus Operating status of the order
orderType OrderType 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<LimitType> 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 Timestamp of order creation
updatedAt Optional<Long> Timestamp of the latest order update
terminatedAt Optional<Long> Timestamp 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
retrieved-deposit Order is generated automatically to move the funds that are too small to cover the fee (dust) from the proxy to the main wallet/custody with next sufficient deposit order

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 canceled
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
atomic-settlement-reservation-completed all the orders for clearloop settlement can proceed and funds are reserved

Limit Types

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

Blockchain Transaction Type

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

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 Timestamp of portfolio creation
updatedAt Optional<Long> Timestamp 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 belo
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

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

Wallet

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 Timestamp of wallet creation
updatedAt Optional<Long> Timestamp 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)

WalletEmbedded

Field Data type Description
depositTargets List<WalletDepositTarget> List of deposit targets attached to the wallet
outstandingBalance Optional<BigDecimal> Amount of outstanding balances, if any

WalletDepositTarget

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

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). This value is mandatory for Custody, Trading or Settlement Lite portfolios.
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

Address Book - BankAccount

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 Timestamp of bank account creation
updatedAt Optional<Long> Timestamp 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):

Address Book - 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
isWhitelist Boolean Defines, if the address is whitelisted or not
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 Timestamp of crypto address creation
updatedAt Optional<Long> Timestamp of last crypto address update

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
counterpartyDescription String Counterparty description as shown on the Copper platform
networkTag String Network Tag as shown on the Copper platform
counterpartyType CounterpartyType Counterparty type indicated access type to the network
_embedded Optional<CounterpartyEmbedded> Additional information of the counterparty

Counterparty Types

Name Description
standard has full access to the network
lite has limited access to the network

Counterparty Embedded

Name Data type
counterpartyConnection Optional<CounterpartyConnection>
counterpartyDetails Optional<CounterpartyDetails>

Counterparty Connection

Name Data type Description
connectionId String Unique identifier of a counterparty connection on the Copper platform
requestorCounterpartyId String Identifier of a counterparty who requested a connection
receiverCounterpartyId String Identifier of a counterparty who received a connection request
requestStatus RequestStatus Status of the connection

Counterparty Request Status

Name Description
accepted Accepted connection
pending Pending connection
declined Declined connection

Counterparty Details

Name Data type Description
connectionId String Unique identifier of a counterparty connection on the Copper platform
counterpartyAddress Optional<String> Counterparty address
counterpartyEmail Optional<String> Counterparty email
counterpartyPhoneNumber Optional<String> Counterparty phone number

DeliveryType

Enum with the following values:

Name Data type Description
free-of-payment String Settlement order type: free of payment
payment-vs-payment String (default) Settlement order type: payment versus payment

Changelog

January 2024

November 2023

January 2023

November 2022

August 2022

July 2022

May 2022

February 2022

December 2021

November 2021

October 2021