Skip to content

How to implement account transfers

Overview

Upvest offers Account Transfers to give end users the ability to initiate the request directly on the clients’ User Interface (UI) / app.

Prior to instructing an account transfer via API

Prior to submitting the request via API on transfer, the end user initiates the process in our client's UI. Once everything is validated and the form has sufficient information, the account transfer process can be triggered and the API request is sent to Upvest. Validation on our client’s side includes:

  1. ISIN Validation: Client checks that ISIN is included in the enabled ISIN list.
  2. Account Check: Client checks that account is active.

Transfer process

The process of account transfers requested via API is similar for both incoming and outgoing, where each transfer goes through the following statuses. These are dependent on the statues of the underlying individual securities transfers.

Each position within account transfer also has its own status transition, which is both described in the Securities Transfers API user guide and the table below.

StatusDescription
NEWThe transfer request has been submitted and will be validated.
PROCESSINGThe transfer has been instructed and is being processed.
SETTLEDThe transfer was executed at the custodian level. The units will be debited from the users account. All the individual positions within the account transfer have settled.
PARTIALLY_SETTLEDOnly part of an account transfer is settled (i.e., only part of the individual positions have settled).
CANCELLEDThe account transfer was cancelled. Final state. To start the same account transfer again a new one has to be created.

Please be aware that this list of statuses may be extended in the future to accommodate additional use cases and functionalities

An account transfer where no instruments are specified in the list within the request is transferred in full. This is applicable to outgoing transfers only.

Create an incoming account transfer

POST /account_transfers

{
  "direction": "INCOMING",
  "user_id": "7e9a0529-d289-4f4a-ae01-c2cd013d582e",
  "account_id": "d396b7c3-aa67-488a-8e39-4a1a7cbeb9f4",
  "transfer_type": "NO_OWNER_CHANGE",
  "settlement_reference": "b82dc5985558fdr2",
  "instruments": [
    {
      "id": "US0378331005",
      "id_type": "ISIN",
      "quantity": "10"
    },
    {
      "id": "US64110L1061",
      "id_type": "ISIN",
      "quantity": "5"
    }
  ],
  "counterparty": {
    "bic": "ABCDDEFFXXX",
    "account_number": "1234567891",
    "name": "Max Mustermann"
  }
}

Create an outgoing account transfer

POST /account_transfers

{
  "direction": "OUTGOING",
  "user_id": "7e9a0529-d289-4f4a-ae01-c2cd013d582e",
  "account_id": "d396b7c3-aa67-488a-8e39-4a1a7cbeb9f4",
  "transfer_type": "NO_OWNER_CHANGE",
  "settlement_reference": "b82dc5985558fdr2",
  "instruments": [
    {
      "id": "US0378331005",
      "id_type": "ISIN",
      "quantity": "10"
    },
    {
      "id": "US64110L1061",
      "id_type": "ISIN",
      "quantity": "5"
    }
  ],
  "counterparty": {
    "bic": "ABCDDEFFXXX",
    "account_number": "1234567891",
    "name": "Max Mustermann"
  }
}

Request fields

In the transfers request, you must populate the fields marked as Required. Other fields remain optional.

FieldRequired/OptionalDescription
user_idRequiredUser unique identifier.
account_idRequiredAccount unique identifier.
transfer_typeRequiredType of the account transfer. Currently, only NO_OWNER_CHANGE (no change of ownership) is supported.
directionRequiredThe following values are supported:
INCOMING: Transfer is incoming to the user.
OUTGOING: Transfer is outgoing from the user.
settlement_referenceRequiredUnique identifier of the account transfer. Useful for API consumers to build special logic on their side.
instruments.[n].idRequiredISIN (International account Identification Number) or other identity (depends on instruments.[n].id_type) of the security to be transferred.
instruments.[n].id_typeRequiredType of the instruments.[n].id. Currently, only ISIN (International account Identification Number) is supported.
instruments.[n].quantityRequiredThe quantity of the instrument to move in or out. The value supported is maximum 15 digits including decimal place.
Note: For INCOMING the end user ensures that they don't sell their instruments on the counter-broker to enable smooth transfer of their instruments on Upvest platform.
counterparty.bicRequiredBusiness Identifier Code (also known as SWIFT-BIC, BIC, SWIFT ID or SWIFT code) ISO 9362.
counterparty.nameOptionalThe end user’s name at the counterparty's broker.
The name is going to be split into 4 lines of 35 characters, the split is space based. This means that even if the name is exactly 140 of length, we may drop out the last parts if they don't fit into 4x35.
counterparty.account_numberOptionalThe account number is composed of a valid Swift charset with a max length of 28 if provided. The account number helps other brokers identify the owner of the assets.
trade_dateOptionalThe forecast date when the trade takes place. The value will change to ensure market match.
If provided, usually T+1 is sufficient. Depending on the market, this means valid working days.
settlement_dateOptionalThe forecast date when the settlement takes place. The value will change to ensure market match. However, the effective settlement date might be the same date or future one.
If provided, usually T+2 is sufficient or trade_date + 1. Depending on the market, this means valid working days.

Response fields

Only additional fields not present in the request are listed below.

FieldRequired/OptionalDescription
idRequiredAccount transfer request unique identifier.
created_atRequiredDate and time when the resource was created. RFC 3339-5, ISO8601 UTC
updated_atRequiredDate and time when the resource was updated. RFC 3339-5, ISO8601 UTC
statusRequiredStatus of the account transfer:
NEW - account transfer is created but not started processing
PROCESSING - account transfer is in processing
SETTLED - account transfer was successfully settled
CANCELLED - account transfer was cancelled
instruments.[n].quantityOptionalThe quantity of instruments settled.
This field is relevant for the future to support more complex scenarios such as partial settlements
instruments.[n].transfer_idRequiredTransfer request unique identifier of the single position within the account transfer.
instruments.[n].statusRequiredStatus of the transfer of the single position within the account transfer:
NEW - Securities transfer is created but not started processing
PROCESSING - Securities transfer is in processing
SETTLED - Securities transfer was successfully settled
CANCELLED - Securities transfer was cancelled.

Get account transfer by ID

You can retrieve details on a specific account transfer by using the transfer's account_id in the request as shown in the example below.

GET /account_transfers=63da4452-2dd3-4414-a7ca-66c0e3e89645

{
  "id": "63da4452-2dd3-4414-a7ca-66c0e3e89645",
  "created_at": "2025-01-22T14:10:00.00Z",
  "updated_at": "2025-01-22T14:12:34.56Z",
  "direction": "INCOMING",
  "status": "NEW",
  "transfer_type": "NO_OWNER_CHANGE",
  "instruments": [
    {
      "id": "US0378331005",
      "id_type": "ISIN",
      "quantity": "10",
      "status": "NEW",
      "transfer_id": "9637e68f-7065-4131-a072-6d57044ebd8c"
    },
    {
      "id": "US64110L1061",
      "id_type": "ISIN",
      "quantity": "5",
      "status": "NEW",
      "transfer_id": "c2f84524-3f05-4849-909c-2998803327d3"
    }
  ],
  "user_id": "7e9a0529-d289-4f4a-ae01-c2cd013d582e",
  "account_id": "d396b7c3-aa67-488a-8e39-4a1a7cbeb9f4",
  "settlement_reference": "b82dc5985558fdr2",
  "counterparty": {
    "bic": "ABCDDEFFXXX",
    "account_number": "1234567891",
    "name": "Max Mustermann"
  }
}