Skip to content

Quick start


Context

This page will take you through the typical steps to integrate with InvestSuite's Robo Advisor. Below sequence diagram describes the basic happy path:

  • Authenticating to our API
  • Onboarding a user on our platform
  • Funding a portfolio
  • Optimizing (rebalancing) the portfolio
  • Getting the orders from this optimization
  • Updating the portfolio once these orders have been placed at the broker

Postman collection

These steps are also available as a Postman collection. Get in touch with us through your sales contact.

For an exhaustive integration solution (including non-happy path), see the example middleware design.

Overview

CustomerCustomerBroker/CustodianBroker/CustodianClient MiddlewareClient MiddlewareIntegration APIRobo Advisor BackendIntegration APIRobo Advisor BackendOptimizer APIInvestSuite SaaSOptimizer APIInvestSuite SaaSAuthentication1. POST /auth/logintokenOnboarding2. POST /users/user.id3. GET /robo-advisor/policies/policy.id3. POST /portfolios/with user.id and policy.idportfolio.idFundingTransfer cash(Simulated here by meansof a paper portfolio)OKFunding event4. POST /portfolios/{id}/transactions/4. PATCH /portfolios/{id}/Rebalancingloop[Recurring process and triggered by a change in portfolio holdings]optimize()Optimization5. GET /portfolios/{portfoflio_id}/optimizations/{optimization_id}OptimizationsPlace ordersTransactions6. POST /portfolio/{id}/transactions7. PATCH /portfolios/{id}/

Authentication phase

1. Authenticate

We follow the standard OpenID Connect schema. See Authentication.

Onboarding phase

This describes the technical flow. To accomodate various business requirements, see Onboarding.

2. Create a user

Create a user for your customer so that in the next step you can define that user as owner of a portfolio. See Users.

POST /users/ HTTP/1.1
Host: api.sandbox.investsuite.com
Content-Type: application/json
Authorization: Bearer {string}
{
    "external_id": "unique_external_identity_id_2809",
    "first_name": "Ashok",
    "last_name": "Kumar",
    "email": "ashok.kumar@example.com",
    "phone": "+123456789",
    "counter_account": {
        bank_account_number: "BE01234567891234",
        bank_account_type: "IBAN",
        bank_id: "IDQMIE2D"
    },
    "feature_flags": [
        "CONSOLE",
        "ROBO_ADVISOR",
        "SELF_INVESTOR"
    ],
    "language": "en-US"
    "status": "WAITING_FOR_VERIFICATION"
}

Save the user.id from the response body to use in the next step.

3. Create a portfolio

Get a policy

To optimize a portfolio it has to reference a policy: an investment strategy defined by the bank. Such strategy holds the constraints for the optimization algorithm to take into account when rendering order recommendations, for instance the minimum number of stocks within a certain sector or region.

Either you already have a policy.id or (for the sake of example) get (any) valid policy.id by through the following API call, see Policies.

GET /robo-advisor/policies/ HTTP/1.1
Host: api.sandbox.investsuite.com
Authorization: Bearer {access_token_string}

Save the policy.id from the response body to use in the next step.

Create portfolio

We create a new Robo Advisor Portfolio as follows:

  • Specify the discretionary mandate: config.manager="ROBO_ADVISOR_DISCRETIONARY". This sort of mandate comprehends that the portfolio is fully managed by the Robo Advisor, without the need for your customer to intervene. See Glossary.
  • Specify paper money type (as opposed to real money) to simulate trades: "money_type": "PAPER_MONEY". See Glossary.
  • Specify the user from step 2 as owner: "owned_by_user_id": "U01F5WYKRRXZHXT9S6FF1JZNJVZ".
  • Specify the policy as manager setting is required for the Robo Advisor's optimizer algorithm: config.manager_settings.policy_id="Y01EF46X9XB437JS4678X0K529C".

See Portfolios.

POST /portfolios/ HTTP/1.1
Host: api.sandbox.investsuite.com
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Content-Type: application/json
Authorization: Bearer {string}
{
    "external_id":"your-bank-portfolio-1",
    "name":"General investing",
    "owned_by_user_id":"U01F5WYKRRXZHXT9S6FF1JZNJVZ",
    "base_currency":"USD",
    "money_type":"PAPER_MONEY",
    "config":{
        "manager":"ROBO_ADVISOR_DISCRETIONARY",
        "manager_version":1,
        "manager_settings":{
            "goal_id":"L01EF46X4872VVN0QRW4XF2ZP6W",    // Optional
            "horizon_id":"H01EQ3429CY6Y2NW0ZF8A8Y2FYJ", // Optional
            "policy_id":"Y01EF46X9XB437JS4678X0K529C"  
        }
    },
    "portfolio":{
        "$USD":10000
    }
}

Response body:

{
    "external_id": "your-bank-portfolio-1",
    "owned_by_user_id": "U01F5WYKRRXZHXT9S6FF1JZNJVZ",
    "base_currency": "USD",
    "money_type": "PAPER_MONEY",
    "config":{
        "manager": "ROBO_ADVISOR_DISCRETIONARY",
        "manager_version":1,
        "manager_settings": {
            "policy_id": "Y01EF46X9XB437JS4678X0K529C",
            "active": true
        }
    },
    "snapshot_datetime": null,
    "funded_since": null,
    "id": "P01F8ZSNV0J45R9DFZ3D7D8C26F",
    "creation_datetime": "2021-06-24T19:59:15.474241+00:00",
    "version": 1,
    "version_datetime": "2021-06-24T19:59:15.474241+00:00",
    "version_authored_by_portfolio_id": "U01EJQSYGYQJJ5GNFM4ZXW59Q0X",
    "deleted": false,
    "status": "WAITING_FOR_FUNDS"
}

Save the portfolio.id from the response body to use in the next step.

Funding phase

This describes the technical flow. To accomodate various business requirements, see Funding.

4. Fund the portfolio

In this step we're creating a cash transaction, followed by an update to the portfolio holdings. See Transactions.

Create cash transaction

POST /portfolios/P01F8ZSNV0J45R9DFZ3D7D8C26F/transactions/ HTTP/1.1
Host: api.sandbox.investsuite.com
Content-Type: application/json
Authorization: Bearer {string}

{
    "external_id": "P01FFMGXDPSZ2HKZD4G55T6YHHD/2014087240",
    "movements": [
        {
            "external_id": "13891096285",
            "type": "CASH_DEPOSIT",
            "status": "SETTLED",
            "datetime": "2021-09-27T00:00:00+00:00",
            "instrument_id": "$USD",
            "quantity": 10000.0,
        }
    ],
}

Update holdings

Add an initial amount for the Robo Advisor to invest the portfolio you just created. The currency has to match the one defined in the portfolio field base_currency.

PATCH /portfolios/P01F8ZSNV0J45R9DFZ3D7D8C26F/ HTTP/1.1
Host: api.sandbox.investsuite.com
Content-Type: application/json
Authorization: Bearer {string}

{
    "portfolio": {
        "$USD": 10000.0
    }
}

Rebalancing phase

This describes the technical flow. To accomodate various business requirements, see Rebalancing.

Funding the Portfolio (or updating the Portfolio's holdings in general) triggers an optimization. A couple of seconds after the previous step, it should be available. See Optimization.

Issue a GET request to retrieve order recommendations:

GET /portfolios/P01F8ZSNV0J45R9DFZ3D7D8C26F/optimizations/latest/ HTTP/1.1
Host: api.sandbox.investsuite.com
Content-Type: application/json
Authorization: Bearer {string}

The response body contains various fields, inluding the recommended orders:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
{
  "current_solution": {
    "objective_value": -2.3899945188058256e-05,
    "portfolio": {
      "BE78468R1014": 3,
      "$USD": 402.52
    },
    "look_through": {
      "asset_classes": {
        "alternatives": 0.0,
        "bonds": 1.0,
        "commodities": 0.0,
        "stocks": 0.0,
        "cash": 0.0
      },
      "regions": {
        "bonds": {
          "asia_pacific_developed": 0.0,
          "emerging": 0.0,
          "europe_developed": 0.0,
          "north_america": 1.0
        },
        "stocks": {
          "asia_pacific_developed": 0.0,
          "emerging": 0.0,
          "europe_developed": 0.0,
          "north_america": 0.0
        }
      },
      "bond_types": null,
      "sectors": {
        "basic_materials": 0.0,
        "consumer_cyclical": 0.0,
        "consumer_defensive": 0.0,
        "communication_services": 0.0,
        "energy": 0.0,
        "financial_services": 0.0,
        "healthcare": 0.0,
        "industrials": 0.0,
        "real_estate": 0.0,
        "technology": 0.0,
        "utilities": 0.0
      }
    }
  },
  "optimal_solution": {
    "objective_value": 0.001359509844724587,
    "portfolio": {
      "BE4642886612": 0.76,
      "BE78468R1014": 3,
      "BE4642863926": 0.7381,
      "BE46429B2676": 3.7190000000000003,
      "BE78468R2004": 3.0000000000000004,
      "$USD": 14.769662844999981
    },
    "look_through": {
      "asset_classes": {
        "alternatives": 0.0,
        "bonds": 0.7986485447656201,
        "commodities": 0.0,
        "stocks": 0.20135145523437992,
        "cash": 0.0
      },
      "regions": {
        "bonds": {
          "asia_pacific_developed": 0.0,
          "emerging": 0.0,
          "europe_developed": 0.0,
          "north_america": 1.0
        },
        "stocks": {
          "asia_pacific_developed": 0.09369676320272571,
          "emerging": 0.0,
          "europe_developed": 0.1799403747870528,
          "north_america": 0.7263628620102215
        }
      },
      "bond_types": null,
      "sectors": {
        "basic_materials": 0.046054619609495716,
        "consumer_cyclical": 0.13806308600212508,
        "consumer_defensive": 0.07094628258129534,
        "communication_services": 0.022473042495950425,
        "energy": 0.03446538322470511,
        "financial_services": 0.16124155877170626,
        "healthcare": 0.12224125679967916,
        "industrials": 0.11992341101283713,
        "real_estate": 0.0,
        "technology": 0.2563740870896863,
        "utilities": 0.02821727241251957
      }
    }
  },
  "portfolio_update": {
    "is_recommended": true,
    "orders": {
      "BE4642886612": {
        "shares": 0.76,
        "expected_share_price": 130.09,
        "expected_transaction_cost": 0.4943420000000001
      },
      "BE4642863926": {
        "shares": 0.7381,
        "expected_share_price": 130.31,
        "expected_transaction_cost": 0.48090905500000003
      },
      "BE46429B2676": {
        "shares": 3.719,
        "expected_share_price": 26.58,
        "expected_transaction_cost": 0.4942551
      },
      "BE78468R2004": {
        "shares": 3,
        "expected_share_price": 30.64,
        "expected_transaction_cost": 0.4596
      }
    }
  },
  "id": "O01FGNGNS3R3836WB3JHD22J748",
  "creation_datetime": "2021-09-28T06:15:06.613287+00:00",
  "version": 1,
  "version_datetime": "2021-09-28T06:15:06.613287+00:00",
  "version_authored_by_user_id": "UXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "deleted": false
}

6. Create transactions

Notify Robo Advisor that the orders from the previous step (portfolio_update.orders) were placed at the broker, by creating Transactions. See Transactions.

POST /portfolios/P01F8ZSNV0J45R9DFZ3D7D8C26F/transactions/ HTTP/1.1
Host: api.sandbox.investsuite.com
Content-Type: application/json
Authorization: Bearer {string}

[
    {
        "movements": [
            {
                "type": "BUY",
                "status": "SETTLED",
                "datetime": "2021-09-24T06:15:01.999300+00:00",
                "instrument_id": "BE4642886612",
                "quantity": 2
            },
            {
                "type": "SELL",
                "status": "SETTLED",
                "datetime": "2021-09-24T06:15:01.999300+00:00",
                "instrument_id": "$USD",
                "quantity": -125
            }
        ]
    },
    {
        "movements": [
            {
                "type": "BUY",
                "status": "SETTLED",
                "datetime": "2021-09-24T06:15:01.930643+00:00",
                "instrument_id": "BE4642863926",
                "quantity": 3
            },
            {
                "type": "SELL",
                "status": "SETTLED",
                "datetime": "2021-09-24T06:15:01.999300+00:00",
                "instrument_id": "$USD",
                "quantity": -350.50
            }
        ]
    }
]

7. Update holdings

Next update the Portfolio holdings to reflect the bought instrumemts.

PATCH /portfolios/P01F8ZSNV0J45R9DFZ3D7D8C26F/ HTTP/1.1
Host: api.sandbox.investsuite.com
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Content-Type: application/json
Authorization: Bearer {string}

"portfolio": {
    "$USD": 9520,
    "BE4642886612": 2,
    "BE4642863926": 3
}

This will re-trigger the optimizer.

When the recommended orders endpoint is queried again, the response should indicate that the Portfolio is now optimal (in line with the investment policy used by the optimizer) returning no recommendations.

GET /portfolios/P01F8ZSNV0J45R9DFZ3D7D8C26F/optimizations/latest/ HTTP/1.1
Host: api.sandbox.investsuite.com
Content-Type: application/json
Authorization: Bearer {string}

Response body:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{
  "current_solution": {
    ...
  },
  "optimal_solution": {
    ...
  },
  "portfolio_update": {
    "is_recommended": false,
    "orders": {
    }
  },
  "id": "O01FGNGNS3R3836WB3JHD22J748",
  "creation_datetime": "2021-09-28T06:15:06.613287+00:00",
  "version": 1,
  "version_datetime": "2021-09-28T06:15:06.613287+00:00",
  "version_authored_by_user_id": "UXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "deleted": false
}