Introduction
Here at WiseAlpha we are leading the digital revolution in the multi-trillion corporate bond market with a mission to create fair access for all. We are delighted to partner with you.
The WiseAlpha API provides access to the WiseAlpha Fractional Bond Market where customers can trade corporate bonds.
We provide two types of API access, Super accounts and Individual accounts. Super accounts (typically Fintechs, Banks and Online investment platforms) can onboard customers and route orders directly to the WiseAlpha market from their Customers on a real time execution basis. Individual accounts can access information and execute trades on behalf of their own account.
When a Customer is on-boarded by a Super account, a series of steps must be taken including KYC/AML so that WiseAlpha can comply with its regulatory requirements. If you think that these steps can be simplified because of your own regulatory permissions and putting in place a suitable KYC/AML reliance agreement with us then please contact us.
The WiseAlpha API is REST-based and returns responses in JSON.
We have usage examples in cURL and Python. You can view code examples in the area to the right, and you can switch between shell (i.e., using bash, cURL and jq) and Python.
The root URL for all requests to the WiseAlpha production system is
https://api.wisealpha.com/v1/
. The production system will not be available until V1 is fully
released, but a sandbox version is available at https://api-sandbox.wisealpha.com/v1/
.
General
We publish a Corporate Bond Investment Glossary which is useful if you're unfamiliar with some of the terms used in this documentation.
Authentication
Token based authentication
To authorize, use this code:
import requests
headers = {'Authorization': 'Token $API_KEY'}
api = requests.get('$API_ROOT_URL/api_endpoint_here', headers=headers)
# With shell, you can just pass the correct header with each request
curl "$API_ROOT_URL/api_endpoint_here"
-H "Authorization: Token $API_KEY"
Make sure to replace
$API_KEY
with your API key.
WiseAlpha uses API keys to allow access to the API. Access is limited to accounts that have been created by the account accessing the API. If you want to make API calls on behalf of another user see OAuth.
WiseAlpha expects for the API key to be included in all API requests to the server in a header that looks like the following:
Authorization: Token $API_KEY
In the code examples, we use the string $API_KEY
as a substitute for your API key.
OAuth 2.0
WiseAlpha also supports an OAuth 2.0 flow in order to make calls on behalf of a user. In order to do this you will need to set-up an application in the developer portal. Refer to the OAuth section for more information.
Expansion
Some endpoints will detail an Available Expansions section. This will detail what items maybe be optionally returned by the endpoint. To use an expansion include expand=expansion_name
in the query string you send to the endpoint. Some endpoints may include multi-level expansions. Nest expansions are of the form expand=parent__child
Field Exclusion
Some endpoints allow field exclusion, this is done through providing the query string exclude=field_name
. Nested exclusions are also supported and can be used like exclude=field__child_field
Field Inclusion
Some endpoints allow field inclusion, this is done through providing the query string only=field_name
. Nested inclusions are also supported and can be used like only=field__child_field
. All non-included fields will be excluded.
Pagination
api = requests.get('$API_ROOT_URL/customers/',
params={'offset': 5, 'limit': 5},
headers=headers)
curl -s "$API_ROOT_URL/customers/?offset=5&limit=5" \
-H 'Authorization: Token $API_KEY' | jq .
Returns the following JSON pagination object:
{
"count":20,
"next":"$API_ROOT_URL/customers/?limit=5&offset=10",
"previous":"$API_ROOT_URL/customers/?limit=5",
"results":[
{
"customer_id":"10000001",
"email":"user5@wisealpha.com",
...
}
...
]
}
For most lists of objects, you can limit the number of results returned
via parameters to the GET
request.
- To limit the number of results returned, set the parameter
limit
- To set the first result to return, set the parameter
offset
So a request to $API_ROOT_URL/customers/?offset=5&limit=5
will return the second page of five
senior secured bonds.
Any request to a list resource returns a pagination object with the following fields:
Name | Description | Type |
---|---|---|
count | Total number of results available | Integer |
next | Resource URL for the subsequent page of results | String |
previous | Resource URL for the previous page of results | String |
results | Results array | Array |
If no limit is supplied, then the limit defaults to 100.
Ordering
api = requests.get('$API_ROOT_URL/customers/',
params={'ordering': '-date_joined',},
headers=headers)
curl -s "$API_ROOT_URL/customers/?ordering=-date_joined" \
-H 'Authorization: Token $API_KEY' | jq .
Will order the customer list in descending order of the
date_joined
field
List endpoints will provide details on the fields that the returned data can be ordered on. Prefix a field with -
to order by the field descending, e.g. -created
will return the data by the created field in descending order.
Filtering
api = requests.get('$API_ROOT_URL/customers/',
params={'last_name__istartswith': 'bar', 'first_name__icontains': 'foo'},
headers=headers)
curl -s "$API_ROOT_URL/customers/?last_name__istartswith=bar&first_name__icontains=foo" \
-H 'Authorization: Token $API_KEY' | jq .
Will filter the customer by customers who's last name starts with bar and who's first name contains foo (both case insensitive)
List endpoints will detail all the fields that support filtering and the lookups supported. A description of the lookups is given below. The filter string is formed by joining the field name and the lookup name with a __
. E.g. filtering the last_name
field to find last names beginning with bar
(case insensitive) would be done by providing the query string argument last_name__istartswith=bar
.
Text field lookups
Name | Description |
---|---|
exact | Filter by exact matches |
iexact | Filter by exact matches (case insensitive) |
contains | Filter when the field contains the value |
icontains | Filter when the field contains the value (case insensitive) |
startswith | Filter when the field starts with the value |
istartswith | Filter when the field starts with the value (case insensitive) |
endswith | Filter when the field ends with the value |
iendswith | Filter when the field ends with the value (case insensitive) |
Datetime field lookups
Name | Description |
---|---|
gt | Filter by records where the datetime is greater than |
gte | Filter by records where the datetime is greater than or equal |
lt | Filter by records where the datetime is less than |
lte | Filter by records where the datetime is less than or equal |
exact | Filter when the datetime matches |
Data types
Throughout the API, in requests and responses, the WiseAlpha API uses the following basic data types.
Data Type | Description |
---|---|
Integer | An integer number, represented by the native JSON number type. |
Decimal | A decimal number represented as a JSON string, e.g. "100.55" . All money amounts are represented in this way. |
Float | A decimal number represented as a JSON number, e.g. 1.123456789 . This type is used when precision is important. |
Boolean | A value of true/false represented by the native JSON Boolean type. |
String | A text string |
DateTime | An ISO 8601 DateTime string, e.g. "2015-01-01T00:00:00+00:00" |
Date | An ISO 8601 calendar date, e.g., "2015-01-01" |
Array | A collection of items |
Currency | A string containing an ISO 4217 currency code |
Customer ID | User accounts are identified using 8-digit integers, zero padded and encoded in a String. E.g., 10000001 . |
In requests, you can use the special value me to target the user account associated with the API key. |
|
Reference ID | Other objects are identified by a reference string, consisting of a type tag, and a zero-padded ID number. E.g., EVENT00000099 |
Country Code | An ISO 3166-1 alpha-2 country code e.g. 'gb' |
Limited Html String | For some product descriptions we return a limited set of HTML. The HTML returned will be valid XHTML and be limited to the tags ['a', 'ul', 'li', 'p', 'div'] and the attributes ['href', 'alt'] . |
Markdown String | Markdown string |
Pricing
The products on WiseAlpha are bought and sold at a price that's a percentage of par. So a price of 100 indicates that a £1 investment will buy £1 of the product. A price of 90 indicates that a £1 investment will buy £1.11 of the product. A price of 110 indicates that a £1 investment will buy £0.90 of the product.
Rate limiting
Currently the only active rate limiting is triggered by failed authentication requests. All other endpoints do not have a rate limit. WiseAlpha reserves the right to impose a rate limit on requests at a later date.
Testing
We provide a sandbox server that you can use to test out creating users, purchasing investments
and responding to events. Updates to this server do not have real world effects,
(and WiseAlpha may occasionally clear out any data contained in this server when re-syncing
with the production system). To access the sandbox server, use the URL root
https://api-sandbox.wisealpha.com/v1/
.
Versioning
Non-breaking API changes may be made at any time by the WiseAlpha team. An example of a non-breaking change would be the addition of a field returned by an endpoint, addition of a new endpoint or additional of an optional parameter to an existing endpoint. Non-breaking changes will appear in the API Version log as a minor version number increase and will be documented and dated.
Breaking API changes will be rolled out under a major version number, will have a new endpoint and will run in parallel with previous versions. In the event of the WiseAlpha team deprecating a previous API release there will be plenty of notice and help to move onto the new endpoints.
API Version 1.0
Release 2020-01-15
- Remove product_ticker from products
Release 2019-10-03:
- Introduce buy_orders and sell_orders entrypoint
- Rename fields in the market request and response for consistency with order objects:
- buys[].buy_type -> buys[].type
- buys[].amount_currency -> buys[].currency
- buys[].amount_of_principal -> buys[].principal
- buys[].amount_of_interest -> buys[].interest
- buys[].amount_total -> buys[].total
- sells[].amount_currency -> sells[].currency
- sells[].amount_of_principal -> sells[].principal
- sells[].amount_of_interest -> sells[].interest
- sells[].amount_of_interest_fees_due -> sells[].service_fee
- sells[].amount_of_sale_fee -> sells[].sale_fee
- sells[].amount_total -> sells[].total
- Make market returned balance the same as balance returned by balances entrypoint.
- market/quote entrypoint: Add a
warnings
field to contain a list of reasons why the resulting market request might fail. - Orders: Introduce original_id to correlate current order with original order.
- order events: Fields in the event were changed after implementation.
- We no longer create a order.filled event when an order enters the
CONFIRM
state.
- We no longer create a order.filled event when an order enters the
Responses
On success we return a suitable HTTP success code
Success Code | Meaning |
---|---|
200 | OK -- The request was successfully processed and/or the requested data returned. |
201 | Created -- We created the object as you requested. |
202 | Accepted -- The request has been accepted for processing, but the processing has not been completed. The request may still fail during offline processing. You will be notified of success/failure via a webhook.. |
We spell out the response code for each request in the examples below. If no response code is given, 200 - OK will be returned.
Errors
{
"email": ["Customer with this Email already exists."]
}
On error, we return a suitable HTTP error code. For many errors, we also return the nature of the error as a JSON fragment as illustrated.
Error Code | Meaning |
---|---|
400 | Bad Request -- The request could not be processed due a client error |
401 | Unauthorized -- Your API key could not be validated. |
403 | Forbidden -- You tried to execute a request that you do not have rights to, i.e. make a trade on an account you do not have permission to trade on. |
404 | Not Found -- The specified resource could not be found. |
405 | Method Not Allowed -- You tried to access an endpoint with a method that it does not accept |
406 | Not Acceptable -- You requested a format that isn't JSON. |
422 | Unprocessable Entity - The request was understood but could not be processed. E.g. there where not sufficient funds available to complete a market order. |
500 | Internal Server Error -- There was an unexpected server side problem. |
503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |
OAuth
In order to create and configure an OAuth application you will need a WiseAlpha account configured with access to the developer portal, contact our partners team if you're interested.
The root URL for all OAuth requests to the WiseAlpha production system is
https://www.wisealpha.com/o/
. The production system will not be available until V1 is fully
released, but a sandbox version is available at https://sandbox.wisealpha.com/o/
. This URL might change before the production system is launched.
Creating an app
Once you can access the developer portal you will be able to create a new application. When creating the application you will need to provide:
- An application name
- The allowed set of redirect URLs
You will be provided with a client_id
and client_secret
which can be modified at creation time. Apps created on the sandbox environment cannot be moved to the production environment so you'll need to create a production app when you're ready to go live.
When creating or editing your application you will see the below fields.
Name | Description |
---|---|
Name | The application name - users will see this when authorizing your application. |
client_id | This publically identifies your application. |
client_secret | This is your application's secret. |
client_type | Either public or confidential depending on if the credentials retrieved can be stored in a secure way. |
authorization_grant_type | Either authorization_code or implicit . Only authorization_code should be used for production applications - see the aside below |
redirect_uris | The set of URIs that the server will return the browser to after the user grants or denies the application's request for access. |
Scopes
In order to request a specific set of scopes when redirecting to the authorization URL, include the scope
parameter with a space separated list of the below scopes. If this is not included, all scopes will be requested.
Name | Description |
---|---|
read_investments | Grants read access to the user's investment portfolio |
read_profile | Grants read access to the user's profile |
write_profile | Grants write access to the user's profile |
trade | Grants access to trade |
fund | Grants access to issue deposit and withdrawal requests |
create_account | Grants access to create new investment accounts |
OAuth 2.0 Authorization code flow
WiseAlpha supports a standard OAuth 2.0 Authorization code grant flow, at it's heart it's very simple:
- You will have a link on your application to connect to people's WiseAlpha accounts
- This link will send a request to WiseAlpha's
authorize
endpoint - The user sees the authorization prompt and approves the app’s request
- The user is redirected back to the application with an authorization code in the query string
- The application exchanges the authorization code for an access token
- The access token allows you to make API calls on behalf of the user limited by the scopes that your application asked the user to approve.
/authorize/
api = requests.get('$OAUTH_ROOT_URL/authorize/?response_type=code&client_id=ZOknOs0kO02ZyUA8Z6eBUL3cJNip2pRUE0Oi6P71&redirect_uri=https%3A%2F%2Fwww.example.com%2Fauthorize&state=zxx5LbYXdbkbRhfUXCHz2SISHkUgMR&scope=read')
curl -s "$OAUTH_ROOT_URL/authorize/?response_type=code&client_id=ZOknOs0kO02ZyUA8Z6eBUL3cJNip2pRUE0Oi6P71&redirect_uri=https%3A%2F%2Fwww.example.com%2Fauthorize&state=zxx5LbYXdbkbRhfUXCHz2SISHkUgMR&scope=read" \
| jq .
Will return the user to the redirect URL indicating if they have or have not accepted the request for access
- GET: The user's browser should be redirect to this URL in order to give them the opportunity to grant access to your application
The user will see a screen like this:
Once the user has granted or denied access to your application their browser will be redirected back to the provided redirect URI.
/token/
The token endpoint can be used to swap an authorization code for an access/refresh token as well as to using a refresh token to get a new access token.
Exchange Authorization Code
Available Methods:
- POST: Exchange an authorization code for an access token.
Name | Description | Data Type |
---|---|---|
grant_type | authorization_code |
String |
code | An authorization code returned by the authorize endpoint. | String |
client_id | Your application's client_id . |
String |
client_secret | Your application's client_secrent . |
String |
Response:
Name | Description | Data Type |
---|---|---|
access_token | An access token. | String |
token_type | Bearer |
String |
expires_in | The seconds until token expiry. | Integer |
refresh_token | A refresh token. | String |
scope | The scopes the access token gives access to. | String |
Refresh Token
Available Methods:
- POST: Exchange an authorization code for an access token.
Name | Description | Data Type |
---|---|---|
grant_type | refresh_token |
String |
refresh_token | A refresh token. | String |
client_id | Your application's client_id . |
String |
client_secret | Your application's client_secrent . |
String |
Response:
Name | Description | Data Type |
---|---|---|
access_token | An access token. | String |
token_type | Bearer |
String |
expires_in | The seconds until token expiry. | Integer |
refresh_token | A refresh token. | String |
scope | The scopes the access token gives access to. | String |
Products
Displaying WiseAlpha market products
The product endpoints contain all the information needed to create a marketplace for WiseAlpha products. WiseAlpha products fit into a number of marketplaces:
- The Main market - this is the main WiseAlpha market, investing requires the
can_invest
permission - The High Yield market - this market contains higher yielding and therefore higher risk products and requires users to have the
can_invest_high_yield
permission. - The Perpetuals market - this market contains AT1 and Perpetuals which requires users to have the
can_invest_perpetuals
permission. - The Special Situation market - this market contains distressed products which requires users to have the
can_invest_special_situations
permission.
Product Data Types
We use the following data types in the product endpoints:
Product object
Name | Description | Data Type |
---|---|---|
product_id | Product id | String |
state | The state of the product, valid states are open , closed , suspended , repaid , defaulted or exchanged |
String-Enum |
market_type | The WiseAlpha marketplace that the product appears in main_market , high_yield , perpetuals , special_situations |
String-Enum |
investment_type | bond |
String-Enum |
seniority | One of not_specified , super_senior_secured , senior_secured , second_lien_secured , unsecured , unsecured_pik or unsecured_at1 |
String-Enum |
categories | List of categories this product falls into. | Array of Product Category objects |
isin_code | International Securities Identification Number | String |
currency | Currency | String |
buy_price | The current market buy price | Decimal |
sell_price | The current market sell price | Decimal |
maturity | The maturity of the bond | Date |
sell_liquidity | The amount of current liquidity in the WiseAlpha marketplace for this product | Decimal |
pending_liquidity | The amount of liquidity that will soon be injected in the WiseAlpha marketplace for this product | Array of Pending Liquidity objects |
interest_period | The interest period | String |
next_interest_payment | The next interest payment date | Date |
borrower | The legal entity that issued the bond | String |
amount_outstanding | The total amount of the bond in issue | Decimal |
coupon | The annual interest rate paid | Decimal |
coupon_string | A description of the coupon. (e.g. 4.875, L+12.0, E+5.25) | String |
coupon_type | A human readable detailed description of the coupon type. (Fixed Rate, Floating Rate, PIK, PIK Toggle) | String |
call_schedule | The products call schedule, e.g.: [{"date": "2019-09-15", "price": "102.75"}, {"date": "2020-09-15", "price": "101.375"}, {"date": "2021-09-15", "price": "100.00"}] |
Array of Call Option objects |
yield_to_maturity | The current yield if bought at the market price and held to maturity. | Decimal |
current_yield | The current yield, ignoring buy price. | Decimal |
rating_moodys | The Moody's rating | String or null , e.g. B3 |
rating_fitch | The Fitch rating | String or null , e.g. BBB |
rating_sandp | The S&P rating | String or null , e.g. B+ |
accrued_interest_rate | The amount of interest accrued per unit invested, e.g. 1p interest accrued for every £1 invested | Float |
company | Company details | Company object |
cashflows | Cashflow details, optionally returned with the cashflows expansion |
Cashflow object |
zero_interest_fees | Is this product a zero fee product? (Deprecated - use discounted_fee_rate instead) | Boolean |
discounted_fee_rate | The discounted fee rate for the product. | Decimal |
product_url | The URL for this product on the WiseAlpha website | String |
total_invested | Returns the total invested in this product. | Decimal |
user_invested | Not included unless specified in an expand, this will return the aggregate amount the calling user holds in the product across all their investment accounts. | Decimal |
num_important_updates | Number of important updates for product | Integer |
access_restrictions | List of access restrictions that apply to this product | Access restrictions object |
first_added_to_market | The date this product was first added to the WiseAlpha market | Date |
last_added_to_market | The date this product was last added to the WiseAlpha market | Date |
annotations | User-specific annotations optionally added with the annotations extension |
User Annotations object |
Company object
Name | Description | Data Type |
---|---|---|
company_id | Company id | String |
company_name | The name of the company | String |
industry | The industry that the company operates in | Industry object |
stock_symbol | A unique reference to a companies stock. Available for publicly listed companies only | String |
description | A description of the company's undertakings | Limited Html String |
borrower_status | One of performing or non-performing |
String-Enum |
website | The company's website | String |
formation_date | The company's formation date | String |
country_of_origin | The country of origin of the company | String |
ownership_status | A description of the current ownership status - e.g. private held, publicly traded, etc | String |
senior_debt | The percentage of the companies capital structure as senior debt | String |
junior_debt | The percentage of the companies capital structure as junior debt | String |
equity | The percentage of the companies capital structure as equity | String |
tile_description | A short description of the company | String |
tile_image | An image that can be used in a product list | String |
logo | A logo that can be used in a product list | String |
capital_structure | A breakdown of the company's capital structure, optionally returned with the company__captital_structure expansion |
Array of Capital Structure objects |
key_financials | Key financial information, optionally returned with the company__key_financials expansion |
Key Financials object |
important_updates | Important updates on the company, optionally returned with the company__important_updates expansion |
Array of Note objects |
Industry object
Name | Description | Data Type |
---|---|---|
key | Identifier for the industry | String |
name | The name of the industry | String |
Capital Structure object
Name | Description | Data Type |
---|---|---|
capital_type | String | |
amount | Decimal | |
currency | String | |
ebitda | Decimal | |
ebitda_interest | Decimal | |
capitalisation | Decimal | |
maturity | Date | |
margin | String | |
footnote | String | |
is_important | Boolean | |
is_total | Boolean |
Key Financials object
Name | Description | Data Type |
---|---|---|
data | Table of key financial information for different years in markdown format | String |
source | The source of the financial information | String |
Note object
Name | Description | Data Type |
---|---|---|
datestamp | DateTime | |
note_html | String |
Cashflow object
Name | Description | Data Type |
---|---|---|
date | The date the cashflow occurs on. | Date |
coupon_rate | The coupon rate of the cashflow. | Decimal |
coupon_amount | The amount to multiple held principal by to get the predicted coupon payment for a fractional bond. | Decimal |
principal_amount | The amount to multiple held principal by to get the predicted principal payment for a fractional bond. | Decimal |
total_amount | The amount to multiple held principal by to get the predicted total cashflow payment for a fractional bond. | Decimal |
Call Option object
Name | Description | Data Type |
---|---|---|
date | The date the call option begins. If set to 'any', the product can be called at any time | Date or String |
price | The price at which the borrower can call at. | Decimal |
Pending Liquidity object
Name | Description | Data Type |
---|---|---|
package_id | The ID of this package | String |
package_type | One of: new-issue , primary-market |
String |
settlement_date | The date on which the liquidity will be injected into the marketplace | Date |
pending_amount | The amount of principal that will be injected into the marketplace | Decimal |
accrued_interest_rate | The amount of accrued interest to pay per unit of principal in this package | Decimal |
Product Category object
Name | Description | Data Type |
---|---|---|
category_id | A unique ID for the category | String |
label | Text to display for the category | String |
Product Access Restrictions
This is a list of strings each of which represents a particular permission required to access this investment.
Access Restriction | Meaning |
---|---|
high_yield |
You need to have answered the High Yield questionnaire to access this investment. |
perpetuals |
You need to be of a suitable investor type and have answered the Perpetuals questionnaire to access this investment. |
special_situations |
You need to be of a suitable investor type and have answered the Special Situations questionnaire to access this investment. |
Access to each of the above markets can be achieved by going through the appropriate
authorisation process, setting investor type and answering questionnaires.
Each user's current restrictions are detailed in the access_restrictions
record in
the Profile object.
Pricing Summary Data
Pricing summary data is generated with respect to a given pricing date. A pricing_date=YYYY-MM-DD
can be passed in via a query string.
Some products have no available pricing, in which case a single field error
will be returned with the message Pricing not enabled for this product
.
Name | Description | Data Type |
---|---|---|
initial_pricing_date | The date where the pricing information starts | Date |
pricing_date | The pricing date the information is generated relative to | Date |
at_pricing_date | The price at the pricing date | Decimal |
one_day_prior | The price one day prior to the pricing date | Decimal |
seven_days_prior | The price seven days prior to the pricing date | Decimal |
twentyeight_days_prior | The price twenty eight days prior to the pricing date | Decimal |
ninety_days_prior | The price ninety days prior to the pricing date | Decimal |
year_start | The price at the year start | Decimal |
User Annotations Object
Extra information specific to the authenticated user and loan
Name | Description | Data Type |
---|---|---|
is_interested | Set true if the user has registered interest in this specific product. Only applies to bond investments. |
Boolean |
/products/
import requests
headers = {'Authorization': 'Token $API_KEY'}
api = requests.get('$API_ROOT_URL/products/?expand=cashflows', headers=headers)
curl "$API_ROOT_URL/products/?expand=cashflows,access_restrictions,annotations&for_user=me"
-H "Authorization: Token $API_KEY" | jq .
The above command returns pagination object containing a list of product objects:
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"product_id": "INVMKT00000001",
"state": "open",
"market_type": "main_market",
"investment_type": "bond",
"seniority": "super_senior_secured",
"categories": ["investment-grade"],
"access_restrictions": [],
"isin_code": "XS1577956516",
"currency": "GBP",
"buy_price": "101.5000",
"sell_price": "101.5000",
"maturity": "2022-08-01",
"sell_liquidity": "0.00",
"pending_liquidity": [
{
"settlement_date": "2018-01-01",
"pending_amount": "100000.00"
}
],
"interest_period": "6m",
"next_interest_payment": "2018-02-01",
"borrower": "NMG Finco plc",
"amount_outstanding": "370000000.00",
"coupon": "5.0000",
"call_schedule": [
{
"date": "2019-09-01",
"price": "102.50"
},
{
"date": "2020-09-01",
"price": "101.25"
},
{
"date": "2021-09-01",
"price": "100.00"
}
],
"yield_to_maturity": "4.7",
"current_yield": "4.9",
"rating_moodys": "B+",
"rating_fitch": "A-",
"rating_sandp": null,
"num_important_updates": 2,
"company": {
"company_id": "CO00000001",
"company_name": "McLaren",
"stock_symbol": "",
"description": "McLaren Technology Group is globally renowned as one of the world’s most illustrious high-technology brands. Since its foundation in 1963, McLaren has been pioneering and innovating in the competitive world of Formula 1, forging a formidable reputation which has seen the racing team win 20 World Championships and over 180 races.\r\n\r\nThe Group has built on its successful racing expertise and diversified to include a global, high-performance sports car business, McLaren Automotive, and a game-changing technology and innovation business, McLaren Applied Technologies.",
"website": "http://www.mclaren.com/",
"formation_date": "1963",
"country_of_origin": "UK",
"ownership_status": "Private",
"image": "https://d1x9604lsph6r7.cloudfront.net/media/cache/cd/24/cd243f12c0c6f5e7c999b46559d63af4.png",
"senior_debt": 19,
"junior_debt": 0,
"equity": 81,
"tile_description": "McLaren Technology Group is globally renowned as one of the world’s most illustrious high-technology brands.",
"tile_image": "https://d1x9604lsph6r7.cloudfront.net/media/cache/cd/24/cd243f12c0c6f5e7c999b46559d63af4.png",
"logo": "https://d1x9604lsph6r7.cloudfront.net/media/cache/25/71/25716d08c1c625febfae715e952258a8.png",
"industry": {
"key": "automotive",
"name": "Automotive"
}
},
"cashflows": {
{
"date": "2018-02-01",
"coupon_rate": "0.0500",
"coupon_amount": "0.0265",
"principal_amount": "0.0000",
"total_amount": "0.0265"
},
...
{
"date": "2022-08-01",
"coupon_rate": "0.0500",
"coupon_amount": "0.0250",
"principal_amount": "1.0000",
"total_amount": "1.0250"
}
},
"annotations": {
"is_interested": false
}
}
]
}
This endpoint retrieves a list of the products available through the WiseAlpha market place. This endpoint supports inclusions and exclusions.
Available Methods
- GET: Returns all investment products currently available on WiseAlpha
Optional Query Strings for GET
Name | Description | Data Type |
---|---|---|
market_type | Filter to return only products of a certain type. Valid values are main_market , high_yield , perpetuals and special_situations |
String-Enum |
isin | Search the endpoint based on the ISIN code. Matches will be returned based on the the product ISIN code starting with the provided filter value. | String |
category | Filter to return products that fall into the given category. E.g., 'investment-grade'. | String |
id | A comma-separated list of IDs of products to return | String (Comma separated list of ids) |
view_closed | If true, fetch all products, including those that are no longer available on the market | Boolean |
Available Expansions
Name | Description |
---|---|
cashflows |
Return the cashflows for the product. |
company__important_updates |
Return important updates for the product's company. |
company__capital_structure |
Return the company capital structure. |
company__key_financials |
Return key financial information for the product's company. |
access_restrictions |
Return any market access restrictions that apply to this investment. |
annotations |
Return user specific information for each product |
The access_restrictions
expansion supports an extra optional request parameter: for_user=<user ID> | 'me'
.
If for_user
is set then the access restrictions returned apply to the given user. If the user has the
necessary permission, that access restriction will not be included in the returned list.
/products/{product_id}/
import requests
headers = {'Authorization': 'Token $API_KEY'}
api = requests.get('$API_ROOT_URL/products/1/', headers=headers)
curl "$API_ROOT_URL/products/1/"
-H "Authorization: Token $API_KEY" | jq .
The above command returns JSON structured like this:
{
"product_id": "INVMKT00000001",
"state": "open",
"market_type": "main_market",
"investment_type": "bond",
"seniority": "super_senior_secured",
"isin_code": "XS1577956516",
"currency": "GBP",
"buy_price": "101.5000",
"sell_price": "101.5000",
"maturity": "2022-08-01",
"sell_liquidity": "0.00",
"pending_liquidity": [
{
"settlement_date": "2018-01-01",
"pending_amount": "100000.00"
}
],
"interest_period": "6m",
"next_interest_payment": "2018-02-01",
"borrower": "NMG Finco plc",
"amount_outstanding": "370000000.00",
"coupon": "5.0000",
"call_schedule": [
{
"date": "2019-09-01",
"price": "102.50"
},
{
"date": "2020-09-01",
"price": "101.25"
},
{
"date": "2021-09-01",
"price": "100.00"
}
],
"yield_to_maturity": "4.7",
"current_yield": "4.9",
"rating_moodys": "B+",
"rating_fitch": "A-",
"rating_sandp": null,
"num_important_updates": 2,
"company": {
"company_id": "CO00000001",
"company_name": "McLaren",
"stock_symbol": "",
"description": "McLaren Technology Group is globally renowned as one of the world’s most illustrious high-technology brands. Since its foundation in 1963, McLaren has been pioneering and innovating in the competitive world of Formula 1, forging a formidable reputation which has seen the racing team win 20 World Championships and over 180 races.\r\n\r\nThe Group has built on its successful racing expertise and diversified to include a global, high-performance sports car business, McLaren Automotive, and a game-changing technology and innovation business, McLaren Applied Technologies.",
"website": "http://www.mclaren.com/",
"formation_date": "1963",
"country_of_origin": "UK",
"ownership_status": "Private",
"image": "https://d1x9604lsph6r7.cloudfront.net/media/cache/cd/24/cd243f12c0c6f5e7c999b46559d63af4.png",
"senior_debt": 19,
"junior_debt": 0,
"equity": 81,
"tile_description": "McLaren Technology Group is globally renowned as one of the world’s most illustrious high-technology brands.",
"tile_image": "https://d1x9604lsph6r7.cloudfront.net/media/cache/cd/24/cd243f12c0c6f5e7c999b46559d63af4.png",
"logo": "https://d1x9604lsph6r7.cloudfront.net/media/cache/25/71/25716d08c1c625febfae715e952258a8.png",
"industry": {
"key": "automotive",
"name": "Automotive"
}
}
}
This endpoint retrieves detailed information about a market product in WiseAlpha. While the list endpoint will only return products currently investible in the WiseAlpha marketplace, the detail endpoint will return products that have since closed (e.g. a bond which has been repaid).
Available Methods
- GET: Returns a product object
Available Expansions
Name | Description |
---|---|
cashflows |
Return the cashflows for the product. |
company__important_updates |
Return important updates for the product's company. |
company__capital_structure |
Return the company capital structure. |
company__key_financials |
Return key financial information for the product's company. |
access_restrictions |
Return any market access restrictions that apply to this investment. |
pricing_summary |
See Pricing Summary Data. |
annotations |
Return user specific information for each product |
The access_restrictions
expansion supports an extra optional request parameter: for_user=<user ID> | 'me'
.
If for_user
is set then the access restrictions returned apply to the given user. If the user has the
necessary permission, that access restriction will not be included in the returned list.
/products/{product_id}/pricing.{format}
import requests
headers = {'Authorization': 'Token $API_KEY'}
api = requests.get('$API_ROOT_URL/products/1/pricing.csv', headers=headers)
curl "$API_ROOT_URL/products/1/pricing.json"
-H "Authorization: Token $API_KEY" | jq .
Available Methods
- GET: Returns the pricing data for the product available either as CSV or JSON depending on the format passed
Data is returned as either JSON:
[
{
"date": "2019-08-06",
"price": "102.5000"
},
{
"date": "2019-08-07",
"price": "102.7000"
},
{
"date": "2019-08-07",
"price": "102.5000"
}
]
Or CSV
2019-08-06,102.5000
2019-08-07,102.7000
2019-08-08,102.5000
/products/{product_id}/annotations
requests.patch('$API_ROOT_URL/products/1/annotations/', data={'is_interested': True}, headers=headers)
curl -s -X POST "$API_ROOT_URL/products/1/annotations/" \
-H "Authorization: Token $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"is_interested": "true"}'
This method is used to update the annotations fields for the given bond. In particular users can set
the is_interested
flag for a specific bond using this endpoint.
Available Methods
- PATCH: Update annotations records
/products/describe_types/
import requests
headers = {'Authorization': 'Token $API_KEY'}
api = requests.get('$API_ROOT_URL/products/describe_types/', headers=headers)
curl "$API_ROOT_URL/products/describe_types/"
-H "Authorization: Token $API_KEY" | jq .
The above command returns a pagination object containing a list of investment type objects:
{
"count": 6,
"next": null,
"previous": null,
"results": [
{
"market_type": "main_market",
"name": "Senior Secured",
"category": "investment",
"description": "A corporate takes out a bond from a bank and this bond is then syndicated amongst a group of lenders.",
"resource_url": "https://api.wisealpha.com/v1/products/?market_type=main_market"
},
{
"market_type": "high_yield",
"name": "High Yield",
"category": "investment",
"description": "High yield bonds ...",
"resource_url": "https://api.wisealpha.com/v1/products/?market_type=high_yield"
},
...
]
}
This endpoint retrieves all product types currently available through WiseAlpha.
Available Methods
- GET: Returns descriptions for all product types currently available through WiseAlpha
Product Type Description Resource
Name | Description | Data Type |
---|---|---|
results[ ].market_type | Product identifier | String |
results[ ].name | Product display name | String |
results[ ].category | Product category | String |
results[ ].description | A plain English description of the product | String |
results[ ].resource_url | Product resource URL | String |
Companies
Company Update Data Types
We use the following data types in the company update endpoints:
Company Update Source
{
"id": 1136,
"name": "lse-gb",
"description": "London Stock Exchange",
"url": "https://www.londonstockexchange.com/",
"image": "https://docs.londonstockexchange.com/sites/default/files/logo.svg"
}
Name | Description | Data Type |
---|---|---|
id | Company Update Source ID | Reference ID |
name | Source name | String |
description | short description about the source | String |
url | URL | String |
image | Image URL | String |
Company Update Object
{
"id": 25079,
"source": {
"id": 1136,
"name": "lse-gb",
"description": "London Stock Exchange",
"url": "https://www.londonstockexchange.com/",
"image": "https://docs.londonstockexchange.com/sites/default/files/logo.svg"
},
"title": "AA 2021Q2 financials updated",
"description": "Please find the newest AA financials here: [https://aggredium.com/company/AABOND/standardized/?data\\_view=ltm'](https://aggredium.com/company/AABOND/standardized/?data_view=ltm')\n\n ",
"published_time": "2020-09-29T11:15:44Z",
"url": "https://aggredium.com/company/AABOND/standardized/?data_view=ltm'",
"provider": "AGGREDIUM",
"type": "COMPANY_NEWS",
"image": null,
"category": "financials update",
"priority": "LOW"
}
Name | Description | Data Type |
---|---|---|
id | Company Update ID | Reference ID |
source | Update source | Company Update Source |
title | Title of the update | String |
description | Description of the update | Markdown String |
published_time | Datetime when the update was published. | DateTime |
url | URL to the original update | String |
provider | Name of the (meta data) provider (e.g. CITY_FALCON , AGGREDIUM , WISEALPHA ) |
String-Enum |
type | Type of update (e.g. COMPANY_NEWS , PRESS ) |
String-Enum |
image | Image URL | String |
category | Category of the update | String |
priority | Priority level assigned to the update (e.g. LOW , MEDIUM , HIGH ) |
String-Enum |
Get list of company updates
URL: GET /companies/{}/company-updates/
Example
GET
request
api = requests.get('$API_ROOT_URL/companies/CO00000001/company-updates/limit=2&offset=10', headers=headers)
curl -s "$API_ROOT_URL/companies/CO00000001/company-updates/limit=2&offset=10" \
-H 'Authorization: Token $API_KEY' | jq .
The above command returns JSON structured like this:
{
"count": 20,
"next": "https://api.wisealpha.com/pubapi/v1/companies/CO00000019/company-updates/?limit=2&offset=12",
"previous": "https://api.wisealpha.com/pubapi/v1/companies/CO00000019/company-updates/?limit=2&offset=8",
"results": [
{
"id": 23766,
"source": {
"id": 1136,
"name": "lse-gb",
"description": "London Stock Exchange",
"url": "https://www.londonstockexchange.com/",
"image": "https://docs.londonstockexchange.com/sites/default/files/logo.svg"
},
"title": "Albert Bridge Cap Form 8.3 AA Plc",
"description": "RNS Number : 9332Y Albert Bridge Capital LLP 14 September 2020 FORM 8.3 PUBLIC OPENING POSITION DISCLOSURE/DEALING DISCLOSURE BY A PERSON WITH INTERESTS IN RELEVANT SECURITIES REPRESENTING 1% OR MORE Rule 8.3 of the Takeover Code (the \"Code\") 1. ...",
"published_time": "2020-09-14T13:04:00Z",
"url": "https://cityfalcon.com/directory/filings/GB/lse-gb/121999940-aa-plc-albert-bridge-cap-form-83-aa-plc",
"provider": "CITY_FALCON",
"type": "COMPANY_NEWS",
"image": "https://cityfalconproduction.blob.core.windows.net/autotweetmedia/domains/logos/79/small.png",
"category": "major_publication",
"priority": "LOW"
},
...
]
}
This endpoint retrieves a list of company updates linked to the current company. Results are arranged in reverse chronological order.
Optional Query Strings for GET
Name | Description | Data Type |
---|---|---|
limit | limit the number of results | Integer |
offset | offset | Integer |
provider | Name of the (meta data) provider (e.g. CITY_FALCON , AGGREDIUM , WISEALPHA ) |
String-Enum |
type | Type of update (e.g. COMPANY_NEWS , PRESS ) |
String-Enum |
priority | Priority level assigned to the update (e.g. LOW , MEDIUM , HIGH ) |
String-Enum |
Company Document Data Types
We use the following data types in the company document endpoints:
Company Document object
{
"reference": "CFD00002095",
"description": "2022 First Six Months Presentation",
"link": "https://web-assets.wisealpha.com/media/company/files/220727115118/Q1_2022_Presentation.pdf",
"order": 0,
"document_type": "Generic"
}
Name | Description | Data Type |
---|---|---|
reference | Company Document reference | Reference ID |
description | Short description of the document | String |
link | URL for uploaded document | String |
order | Number representing display order | Integer |
document_type | Type of document (e.g. Generic , Prospetus ) |
String-Enum |
List or upload company documents
URL: /companies/{company_id}/documents/
This endpoint is used to list and upload documents that are associated with a company. GET is available to ordinary user accounts, but only accounts with operations permissions can POST.
Available Methods:
- GET: Returns all documents linked to the current company. Results are arranged in ascending order based on the
order
field. A direct link to the document will be provided, if available. Otherwise, a source URL will be provided. - POST: Uploads a new document. The document file should be posted to the
file_upload
field.
Example
GET
request
api = requests.get('$API_ROOT_URL/companies/CO00000001/documents/', headers=headers)
curl -s "$API_ROOT_URL/companies/CO00000001/documents/" \
-H 'Authorization: Token $API_KEY' | jq .
The above command returns JSON structured like this:
{
"count": 19,
"next": null,
"previous": null,
"results": [
{
"reference": 2095,
"description": "2022 First Six Months Presentation",
"link": "https://web-assets.wisealpha.com/media/company/files/220727115118/Q1_2022_Presentation.pdf",
"order": 0,
"document_type": "Generic"
},
{
"reference": 2096,
"description": "2022 First Six Months Results",
"link": "https://web-assets.wisealpha.com/media/company/files/220727115118/Q1_2022_Results.pdf",
"order": 1,
"document_type": "Generic"
},
{
"reference": 1941,
"description": "2021 Full Year Results",
"link": "https://s3.eu-west-1.amazonaws.com/aggredium-prod-media/CompanyFiles/123456",
"order": 2,
"document_type": "Generic"
},
{
"reference": 1942,
"description": "Prospectus",
"link": "https://web-assets.wisealpha.com/media/company/files/211111115902/Prospectus.pdf",
"order": 3,
"document_type": "Prospectus"
},
...
]
}
Example
POST
request
api = requests.post('$API_ROOT_URL/companies/CO00000001/documents/',
data = {"description": "Test document description", "file_upload": FILE},
headers=headers)
curl -s -X POST "$API_ROOT_URL/companies/CO00000001/documents/" \
-H 'Authorization: Token $API_KEY' \
-H 'Content-Type: application/json' \
-d '{"description": "Test document description", "file_upload": FILE}' | jq .
The above command returns a company document object.
Get or change a company document
URL: /companies/{company_id}/documents/{document_reference}
This endpoint is used to retrieve, update or delete an uploaded document that is associated with a company. GET is available to ordinary user accounts, but only accounts with operations permissions can PATCH and DELETE.
Available Methods:
- GET: Returns a company document object.
- PATCH: Updates a company document and returns a company document object.
- DELETE: Deletes a company document.
Customer Profiles
These endpoints are used to fetch and update the personal information for WiseAlpha users.
If you have a super account, you can use these endpoints to create managed WiseAlpha users, and progress them through the account onboarding process.
You can also use these endpoints if you are not a super account.
In this case, setting customer_id
to me
in the endpoints targets the user
account associated with the API key. The list
and create
endpoints are only
available to super accounts.
You can find more details of the information we gather and how it is used in the onboarding section of this document.
Customer Profile Data Types
We use the following data types in the profile endpoints:
Profile object
We return this object when details of a WiseAlpha user are requested. It is also used when
creating and updating user information, and subsets of this object are used in the PATCH
method of the /customers/{customer_id}/
endpoint.
{
"customer_id":"10000001",
"email":"user1@example.com",
"title":"mr",
"first_name":"FirstName",
"last_name":"LastName",
"contact_number":null,
"nationality":"GB",
"date_of_birth":null,
"date_joined":"2017-11-23T11:17:05.488037Z",
"address":null,
"previous_addresses":[],
"bank_details":{
"GBP":{
"provided":false,
"last_error":""
},
"EUR":{
"provided":false,
"last_error":""
}
},
"tax_residencies": [],
"investor_type":null,
"user_agreements": {
"client-account-migration": {
"reference": "client-account-migration",
"agreement": "$API_ROOT_URL/customers/me/user-agreements/client-account-migration/",
"choices": [
{
"reference": "move_funds",
"text": "Move Funds To Client Account"
},
{
"reference": "withdraw_funds",
"text": "Withdraw Funds"
}
],
"decision": ""
}
},
"tos_acceptance":{},
"ifisa_agreement_acceptance": null,
"access_restrictions": {
"high_yield": {
"investor_type": true,
"questionnaire": false,
"access_approved": false,
"message": "message"
},
"perpetuals": {
"investor_type": false,
"questionnaire": false,
"access_approved": false,
"message": "message"
},
"special_situations": {
"investor_type": false,
"questionnaire": false,
"access_approved": false,
"message": "message"
}
},
"validation":{
"status":"onboarding",
"can_withdraw":false,
"can_invest_high_yield":false,
"can_invest_perpetuals":false,
"can_invest_special_situations":false,
"next_actions":[
"provide-missing-fields",
"select-investor-type"
],
"can_invest":false,
"aml_check":{
"status":"No Check Performed",
"passed":false
},
"fields_needed":[
"nationality",
"date_of_birth",
"contact_number",
"address",
"bank_details",
"tos_acceptance",
"tax_residencies",
"user_agreement:client-account-migration"
],
"documents":{
"proof_of_address":"not-yet-needed",
"photo_id":"not-yet-needed"
},
"document_info": {},
"questionnaire":{
"high-yield": "not-attempted",
"perpetual": "not-attempted",
"signup": "not-attempted",
"smart-interest": "not-attempted",
"special-situation": "not-attempted"
},
"sale_fee": "0.2500",
"role": "investor",
"account_locked": false
}
}
Name | Description | Data Type |
---|---|---|
customer_id | The ID of the account. | Customer ID |
Email of the user associated with the account. | String | |
title | Title of the user associated with the account. | String |
first_name | First name of the user associated with the account. | String |
last_name | Last name of the user associated with the account. | String |
contact_number | User's telephone number - we occasionally need to contact the user for compliance purposes | String |
nationality | Country code for user's nationality | Country Code |
date_of_birth | Date of birth of the user | Date |
date_joined | The date the user joined wisealpha | DateTime |
address | Current address of the user. | Address object |
previous_addresses | Previous addresses of the user. You should provide addresses to cover the last 3 years. | List of Address objects |
bank_details | The user's bank-account details. Payouts are transferred to this account. | Bank account object |
tax_residencies | The user's current tax residencies. | List of Tax residency objects |
investor_type | The type of this investor | Investor type object (Read Only) |
user_agreements | All the legal agreements relating to the user | User agreements object |
tos_acceptance | Details of when the user accepted the WiseAlpha Terms Of Service | TOS object |
ifisa_agreement_acceptance | Details of when the user accepted the WiseAlpha IF ISA Agreement | TOS object |
access_restrictions | Details of any access restrictions that apply to this account | Access restrictions object (Read Only) |
validation | Details of the user's progress through the Onboarding process | Validation object (Read Only) |
sale_fee | The user's sale fee | Decimal |
role | The user's role | String |
account_locked | The user's account lock status | Boolean |
The email address field must be unique across the WiseAlpha platform. If you try to create an account with a pre-existing email address, or update the email address to match another account, then the API will return an error.
customer_id
, date_joined
, investor_type
, access_restrictions
, validation
and account_locked
are read-only
fields, and cannot be updated by users.
Investor type is set/updated using the /customers/{customer_id}/change_investor_type/
endpoint.
Accounts can be unlocked using the /customers/{customer_id}/unlock-account/
endpoint.
bank_details
is a special object - you can set its value, but when read it just returns
whether the value has been set or not. See the bank account object for details.
Address object
This is the data type used for user addresses in the profile object.
{
"flat_or_apartment_number":null,
"house_name":null,
"house_number":"1",
"address1":"John Street",
"address2":null,
"address3":"London",
"address4":null,
"post_code":"N1 1XX",
"country": "gb",
"from_date":"2016-01-01",
"to_date": null
}
Name | Description | Data Type |
---|---|---|
flat_or_apartment_number | Flat number, if residence is a flat | See note below |
house_name | Name of the house, if it has one | See note below |
house_number | Number of the house, if it has one | See note below |
address1 | e.g., Street name | String |
address2 | Optional String | |
address3 | Town/City name | String |
address4 | Optional String | |
post_code | Post Code/Zip Code | String |
country | Country | Country Code |
from_date | The date the user moved to this address | Date |
to_date | The date the user moved to this address | Optional Date |
Note: You must specify at least one of flat_or_apartment_number
, house_number
, house_name
.
For the address
field in the profile object (i.e., the user's current address),
the to_date
is assumed to be unset, and is ignored.
Bank account object
This object contains the user's bank-account details.
{
"account_name": "FirstName LastName",
"sort_code":"00-00-00",
"account_number":"88668866",
}
Name | Description | Data Type |
---|---|---|
account_name | The name of the account owner | String |
sort_code | The sort code (or BIC) of the bank holding the account | String |
account_number | The account number (or IBAN) | String |
Note that you should specify either sort code and account number or BIC and IBAN. Mixing the two types of bank identifiers is not supported.
When read, we return a data blob with additional information.
{
"provided":true,
"status":"verified",
"last_error":"",
"details": {
"account_name": "FirstName LastName",
"sort_code":"00-00-00",
"account_number":"88668866",
}
}
Name | Description | Data Type |
---|---|---|
provided | Whether bank account details have been provided | Boolean |
status | Whether the account details have been approved for use. One of unverified , verified , rejected , 'request-new' |
String |
last_error | The reason the bank details were rejected, or new details requested. | String |
details | The bank details | Object |
Tax residency object
This object contains details of a tax residency.
{
"country": "gb",
"tax_indentification_number": "QQ123456C"
}
Name | Description | Data Type |
---|---|---|
country | The country of the tax residency | Country Code |
tax_identification_number | The tax identification number | String |
Change investor type object
Not all fields are mandatory for all investor type - see below for more information.
Mandatory fields for all investor types
Name | Description | Data Type |
---|---|---|
investor_type_id | The user's investor type id. | Integer |
annual_income | The user's declared annual income. | Decimal |
annual_income_currency | The currency of the user's declared annual income. | Currency |
net_investible_assets | The user's declared net investible assets. | Decimal |
net_investible_assets_currency | The currency of the user's declared net investible assets | Currency |
Certified High Net Worth Investor type validation
There are no additional fields required for the Certified High Net Worth Investor
type, but either the
annual_income submitted must be at least GBP100,000 or the net_investible_assets submitted must be
at least GBP250,000.
Professional Investor type validation
The additional below fields are required for the Professional Investor
type.
Name | Description | Data Type |
---|---|---|
professional_investment_experience | A description of the customer's professional investment experience. | String |
Advised Investor type validation
The additional below fields are required for the Advised Investor
type.
Name | Description | Data Type |
---|---|---|
advisor_name | The customer's advisors name. | String |
advisor_fca_reference_number | The customer's advisors FCA reference number. | String |
advisor_is_fca_authorised | A confirmation that the customers advisor is FCA authorised - this must be true. | Boolean |
Sophisticated Investor type validation
The additional below fields are required for the Self-Certified Sophisticated Investor
type and at least one of them must
be set to true
. They all refer to activities that must have taken part in the prior 6 months.
Name | Description | Data Type |
---|---|---|
angel | The customer has been a member of a business angel network. | Boolean |
unlisted | The customer has invested in a WiseAlpha product, an unlisted company, P2P, Crowdfunding or a Venture Capital firm. | Boolean |
professional | The customer has worked professionally in the private equity sector, or the provision of finance for small and medium enterprises. | Boolean |
director | The customer has been a directory of a company with £1m+ in turnover. | Boolean |
Investor type summary object
This object is read-only. To set the customer's investor type, you need to use the set-investor-type
{
"investor_type_id": 1,
"investor_type_identifier": "Certified High Net Worth Investor",
"investor_type": "High Net Worth Investor",
"is_retail_restricted": false,
"annual_income": "105000",
"annual_income_currency": "GBP",
"net_investible_assets": "350000",
"net_investible_assets_currency": "GBP",
"professional_investment_experience": null,
"occupation": "CEO",
"date_selected": "2017-11-23T14:08:19.107968Z",
}
Name | Description | Data Type |
---|---|---|
investor_type_id | The customer's investor type id | Integer |
investor_type_identifier | The customer's investor type identifier | String |
investor_type | The text label describing this user's investor type | String |
is_retail_restricted | Set true if the user is a retail investor. Retail investors cannot invest in some of the more sophisticated investments | Boolean |
annual_income | The customer's declared annual income. | Decimal |
annual_income_currency | The currency of the customer's declared annual income. | Currency |
net_investible_assets | The customer's declared net investible assets. | Decimal |
net_investible_assets_currency | The currency of the user's declared net investible assets | Currency |
professional_investment_experience | The customer's professional investment experience | String |
advisor_name | The customer's advisors name. | String |
advisor_fca_reference_number | The customer's advisors FCA reference number. | String |
advisor_is_fca_authorised | A confirmation that the customers advisor is FCA authorised - this must be true. | Boolean |
angel | The customer has been a member of a business angel network. | Boolean |
unlisted | The customer has invested in a WiseAlpha product, an unlisted company, P2P, Crowdfunding or a Venture Capital firm. | Boolean |
professional | The customer has worked professionally in the private equity sector, or the provision of finance for small and medium enterprises. | Boolean |
director | The customer has been a directory of a company with £1m+ in turnover. | Boolean |
date_selected | The date the customer selected their investor type | DateTime |
User agreements object
This object should be written when the customer has accepted the WiseAlpha Terms Of Service. It should consist of a dictionary with the following fields:
{
"client-account-migration": {
"reference": "client-account-migration",
"agreement": "$API_ROOT_URL/customers/me/user-agreements/client-account-migration/",
"choices": [
{
"reference": "move_funds",
"text": "Move Funds To Client Account"
},
{
"reference": "withdraw_funds",
"text": "Withdraw Funds"
}
],
"decision": ""
}
}
Name | Description | Data Type |
---|---|---|
client-account-migration | The client account migration agreement | User agreement object |
User agreement object
This is a general form of all user agreements:
{
"reference": "agreement-reference-identifier",
"agreement": "$API_ROOT_URL/customers/me/user-agreements/agreement-markdown-text/",
"choices": [
{
"reference": "choice_1",
"text": "This is choice #1"
},
{
"reference": "choice_2",
"text": "This is choice #2"
}
],
"decision": ""
}
Name | Description | Data Type |
---|---|---|
reference | An identifier used to reference the agreement | String |
agreement | The URL of the agreement text | String |
choices | The choices available to the user | User agreement choice object |
decision | The record of the user's decision | String |
User agreement choice object
This is the general form for choices in user agreements:
{
"reference": "choice_1",
"text": "This is choice #1"
}
Name | Description | Data Type |
---|---|---|
reference | The identifier of the choice. This value must be submitted as the "decision". | String |
text | Text to display to the user | User agreement object |
TOS object
This object should be written when the customer has accepted the WiseAlpha Terms Of Service. It should consist of a dictionary with the following fields:
{
"date":"2017-11-23T11:17:05.488037Z",
"ip_address": "1.2.3.4"
}
Name | Description | Data Type |
---|---|---|
date | Date the customer accepted the Terms Of Service | DateTime |
ip_address | IP address of the customer's computer when he accepted the Terms Of Service | String |
Access restrictions object
This object details the nature of each access restriction that applies to this user.
For a user to gain access to an investment with a particular restriction, he must satisfy two criteria:
They must be of the correct investor type. In particular
retail_restricted
investors cannot access riskier investments.They must answer an appropriate investment questionnaire to show that they understand the nature of the risks involved.
This object outlines the user's progress in achieving these criteria.
"access_restrictions": {
"high_yield": {
"investor_type": true,
"questionnaire": false,
"access_approved": false,
"message": "message"
},
"perpetuals": {
"investor_type": false,
"questionnaire": false,
"access_approved": false,
"message": "message"
},
"special_situations": {
"investor_type": false,
"questionnaire": false,
"access_approved": false,
"message": "message"
}
},
Each access restriction has the following fields:
Name | Description | Data Type |
---|---|---|
investor_type | Is the user's investor type allowed to access these investments? | Boolean |
questionnaire | Has the user completed the necessary questionnaire for these investments? | Boolean |
message | A brief message describing what the user needs to do to access these investments | String |
access_approved | Has the user got access to these investments. | Boolean |
Note that access_approved
may be false
even if the investor_type
and questionnaire
are true
;
in this case the user access permission is awaiting approval from a member of the WiseAlpha team.
Validation object
This records the customer's progress through the onboarding process.
{
"status":"onboarding",
"can_invest": false,
"can_invest_high_yield": false,
"can_invest_perpetuals": false,
"can_invest_special_situations": false,
"can_withdraw": false,
"next_actions":[
"provide-missing-fields",
"select-investor-type"
],
"fields_needed":[
"date_of_birth",
"contact_number",
"address",
"bank_details",
"tos_acceptance"
],
"aml_check":{
"status":"No Check Performed",
"passed":false
},
"documents":{
"proof_of_address":"not-yet-needed",
"photo_id":"not-yet-needed"
},
"document_info":{},
"questionnaire":{
"high-yield": "not-attempted",
"perpetual": "not-attempted",
"signup": "not-attempted",
"smart-interest": "not-attempted",
"special-situation": "not-attempted"
}
}
Name | Description | Data Type |
---|---|---|
status | The status of the onboarding process | String |
can_invest | Can this user deposit money and buy fractional bonds? | Boolean |
can_invest_high_yield | Can this user invest in the high yield bonds market? | Boolean |
can_invest_perpetuals | Can this user invest in the perpetual market? | Boolean |
can_invest_special_situations | Can this user invest in the special situation market? | Boolean |
can_withdraw | Can this user withdraw funds | Boolean |
next_actions | What actions should the user do next | List of Strings |
fields_needed | If next_actions contains "provide-missing-fields" this list identifies which fields should be provided | List of Strings |
aml_check | The AML check object | |
aml_check.status | The status of the AML check. See [onboarding] for details | String |
aml_check.passed | Whether the AML check has been passed | Boolean |
documents | List of required documents and their current upload status | Map of key-value pairs. |
document_info | Extra information (such as reason document was rejected) to help with uploading the correct document | Map of key-value pairs. |
The keys for the documents
and document_info
maps will be one of the known
document types: photo_id
, proof_of_address
, bank_statement:<currency>
. For documents
other than photo_id
and proof_of_address
, we will not add an entry in documents
unless that document is required.
The values for the documents
map will be one of: not-yet-needed
, required
,
provided
, approved
, rejected
.
If a document is in the rejected
state, then document_info.rejection_reason
will
contain a description of the rejection reason.
More details of the meaning of each of these fields can be found in the onboarding section of this document.
Investor type object
We return a list of these objects from the investor_types
endpoint.
This information should be displayed to the user when he is selecting his investor type.
The title
field should be used in the toggle used to select the investor type.
The intro_title
and intro_content
fields give a brief overview of what each
investor type entails.
The main_title
and main_content
outline the terms the user is agreeing to by
selecting that investor type.
Once a user has selected an investor type, the id
and title
fields are returned
in the user's investor type summary object. The indentifier
field can be used to map the investor
type to it's required fields on submission of a change investor type request.
More details on the investor-type-selection process can be found in the onboarding section of this document.
{
"id":1,
"identifier": "Certified High Net Worth Investor",
"title":"High Net Worth Investor",
"intro_title":" What is a Certified High Net Worth Investor?",
"intro_content":"<p>Description of this investor type.</p>\r\n",
"main_title":"Certified High Net Worth Investor Statement",
"main_content":"<p>What the investor is agreeing to.....</p>"
}
Name | Description | Data Type |
---|---|---|
id | ID of this investor type | Integer |
identifier | A string identifying this investor type, one of Standard Investor , Self-Certified Sophisticated Investor , Professional Investor , Certified High Net Worth Investor or Advised Investor |
String-Enum |
title | Title/identifying string for this investor type | String |
intro_title | Page title to use when presenting this investor type | String |
intro_content | Description of this investor type | HTML String |
main_title | Header for the investor agreement for this investor type | String |
main_content | Investor agreement | HTML String |
Questionnaire object
We return this object via the questionnaire endpoint.
Each question in the questions
array represents a single multiple-choice question.
{
"type":"signup",
"help": "help text",
"questions":[
{
"id":1,
"question":"Question 1?",
"answers":[
{
"id":3,
"answer_text":"Answer 1."
},
{
"id":1,
"answer_text":"Answer 2."
}
],
"mimetype": "text/plain",
"question_type": "radio"
},
...
],
"faqs": [
{
"title": "What are Senior Secured bonds ?",
"link": "https://support.wisealpha.com/glossary/senior-secured"
},
{
"title": "What happens when a corporate borrower defaults ?",
"link": "https://support.wisealpha.com/about-wisealpha/what-happens-if-a-borrower-defaults"
},
{
"title": "How does our secondary market operate ?",
"link": "https://support.wisealpha.com/glossary/secondary-market"
},
{
"title": "When will I receive Interest Payments ?",
"link": "https://support.wisealpha.com/payments-and-fees/when-will-i-receive-interest-payments"
},
{
"title": "What is Yield To Maturity ?",
"link": "https://support.wisealpha.com/glossary/yield-to-maturity"
},
{
"title": "What is Current Yield ?",
"link": "https://support.wisealpha.com/glossary/current-yield"
}
],
"user_status": {
"blocked_message": null,
"num_failed_attempts": 0,
"max_num_failed_attempts": 3,
"num_attempts_remaining": 3,
"passed": false
},
"hash": "680b7d32e5f5b39528b46dd0e4051c41"
}
Name | Description | Data Type |
---|---|---|
type | Questionnaire type | String, either signup , high-yield , special-situation or perpetual |
help | Help text to display if the user fails to pass the questionnaire. | String |
questions | Questions to ask | List of question objects |
faqs | Frequently asked questions relating to this questionnaire | List of FAQ objects |
user_status | If this questionnaire is being retrieved in the context of a user then returned will be the user's current questionnaire status, null otherwise. | A questionnaire user status object. |
Question object
Name | Description | Data Type |
---|---|---|
id | ID of this question | Integer |
question | The question text | String |
mimetype | The mimetype of the question text. | Can be one of text/plain , text/markdown |
question_type | The type of question | Can be one of radio , free_text |
answers | Answers for this question | List of answer objects |
Answer object
Name | Description | Data Type |
---|---|---|
id | ID of this answer | Integer |
answer_text | Text for this answer | String |
FAQ object
Name | Description | Data Type |
---|---|---|
title | FAQ title | String |
link | FAQ link | String |
Questionnaire user status object
Name | Description | Data Type |
---|---|---|
blocked_message | If set, the user has been blocked on the questionnaire. This can be due to an answer having been submitted that needs a compliance action before continuing. | String |
num_failed_attempts | The number of times the user has attempted and failed this questionnaire. | Integer |
max_num_failed_attempts | The maximum number of times the user can fail this questionnaire before being blocked, can be null. | Integer |
num_attempts_remaining | The number of attempts the user had remaining to pass this questionnaire, can be null. | Integer |
passed | Have they passed this questionnaire? | Boolean |
List customers
URL: POST /customers/
Example
GET
request
api = requests.get('$API_ROOT_URL/customers/', headers=headers)
curl -s "$API_ROOT_URL/customers/" \
-H 'Authorization: Token $API_KEY' | jq .
The above command returns pagination object containing a list of managed user accounts associated with the current API key. The resulting JSON is structured like this:
{
"count": 6,
"next": null,
"previous": null,
"results": [
{
"customer_id":"10000001",
"email":"user1@example.com",
"title":"mr",
"first_name":"FirstName",
"last_name":"LastName",
"contact_number":"07777777777",
"nationality":"GB",
"date_of_birth":"2000-01-01",
"date_joined":"2017-11-23T11:17:05.488037Z",
"address":{ address... },
"previous_addresses":[],
"bank_details":{
"provided":true,
"last_error":""
},
"investor_type":null,
"user_agreement": {},
"tos_acceptance":{ },
"ifisa_agreement_acceptance": null,
"validation":{ validation... }
}
...
]
}
Example
POST
request
data = {
"email": "user@example.com",
"first_name": "FirstName",
"last_name": "LastName"
}
api = requests.post('$API_ROOT_URL/customers/', data=data, headers=headers)
curl -s -X POST $API_ROOT_URL/customers/ \
-H 'Authorization: Token $API_KEY' \
-H 'Content-Type: application/json' \
-d '{"email": "user1@example.com","first_name": "FirstName", "last_name": "LastName"}' | jq .
The above command creates a managed user account and associates it with the current API key. On success, it returns the profile object for the resulting user.
{
"customer_id":"10000001",
"email":"user1@example.com",
"title":"mr",
"first_name":"FirstName",
"last_name":"LastName",
"contact_number":null,
"nationality":"GB",
"date_of_birth":null,
"date_joined":"2017-11-23T11:17:05.488037Z",
"address":null,
"previous_addresses":[],
"bank_details":{
"provided":false,
"last_error":""
},
"investor_type":null,
"user_agreement": {},
"tos_acceptance":{},
"ifisa_agreement_acceptance": null,
"validation":{
"status":"onboarding",
"can_withdraw":false,
"can_invest_high_yield":false,
"can_invest_perpetuals":false,
"can_invest_special_situations":false,
"next_actions":[
"provide-missing-fields",
"select-investor-type"
],
"can_invest":false,
"aml_check":{
"status":"No Check Performed",
"passed":false
},
"fields_needed":[
"nationality",
"date_of_birth",
"contact_number",
"address",
"bank_details",
"tos_acceptance"
],
"documents":{
"proof_of_address":"not-yet-needed",
"photo_id":"not-yet-needed"
},
"document_info":{},
"questionnaire":{
"high-yield": "not-attempted",
"perpetual": "not-attempted",
"signup": "not-attempted",
"smart-interest": "not-attempted",
"special-situation": "not-attempted"
}
}
}
This endpoint is used to list and create accounts that have been associated with the API key in use (i.e., "super accounts")
This endpoint is only available to accounts that have been configured as a Super Account. If ordinary users try to use this method, it will return 403 - Permission Denied.
Available Methods:
- GET: Returns all accounts associated with the current API key
- POST: Creates a new account and associates it with the current API key
Supported Ordering Fields
Field Name |
---|
date_joined |
first_name |
last_name |
email |
Supported Filtering
Field Name | Support Lookups |
---|---|
email |
All text lookups supported |
first_name |
All text lookups supported |
last_name |
All text lookups supported |
search |
This will filter by email__icontains , first_name__istartswith , last_name__istartswith or customer_id__icontains |
account_locked |
Valid lookups are account_locked=true and account_locked=false |
GET Request
This endpoint returns a list of all managed users associated with the API key in use. The data is returned as a list of profile object.
POST Request
This endpoint creates a new managed user account and associates it with the current API key.
The email field must be set at this point, but other fields can be set in subsequent PUT
or PATCH
requests.
But note that a user cannot invest until all fields are set and the onboarding process is complete.
Once an account is created, it is associated with the API key used to create the account. The same key will have the rights to make investment requests on behalf of the account. On initial creation, an account is in an unverified state, there is an onboarding process that must be followed to get an account through to the state where it can be used to make investments.
Customer profile
URL: POST /customers/{customer_id}/
## GET request
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/', headers=headers)
## PUT request
data = {
"customer_id":"10000001",
"email":"user1@example.com",
"title":"mr",
"first_name":"FirstName",
"last_name":"LastName",
"contact_number":"07777777777",
"nationality":"GB",
"date_of_birth":"2000-01-01",
"date_joined":"2017-11-23T11:17:05.488037Z",
"address":{
"house_number": "1",
"address1": "Some Street.",
"address3": "London",
"post_code": "N1 1XX",
"from_date":"2016-01-01"
},
"previous_addresses":[],
"bank_details":{
"GBP": {
"account_name": "FirstName LastName",
"sort_code":123456,
"account_number":12345678,
}
}
}
api = requests.put('$API_ROOT_URL/customers/10003074/', data=data, headers=headers)
## PATCH request
data = {
"contact_number":"07777777778",
"previous_addresses":[
{
"house_number": "2",
"address1": "Some Street.",
"address3": "London",
"post_code": "N1 1XX",
"from_date":"2014-01-01",
"to_date":"2016-01-01"
}
],
"tos_acceptance": {
"date":"2017-11-23T11:17:05.488037Z",
"ip_address": "1.2.3.4"
}
}
api = requests.patch('$API_ROOT_URL/customers/10003074/', data=data, headers=headers)
## GET request
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/" \
-H "Authorization: Token $API_KEY" | jq .
## PUT request
read -r -d '' DATA << EOM
{
"customer_id":"10000001",
"email":"user1@example.com",
"title":"mr",
"first_name":"FirstName",
"last_name":"LastName",
"contact_number":"07777777777",
"nationality":"GB",
"date_of_birth":"2000-01-01",
"date_joined":"2017-11-23T11:17:05.488037Z",
"address":{
"house_number": "1",
"address1": "Some Street.",
"address3": "London",
"post_code": "N1 1XX",
"from_date":"2016-01-01"
},
"previous_addresses":[],
"bank_details":{
"GBP": {
"account_name": "FirstName LastName",
"sort_code":123456,
"account_number":12345678,
}
}
}
EOM
curl -s -X PUT "$API_ROOT_URL/customers/10003074/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
## PATCH request
read -r -d '' DATA << EOM
{
"contact_number":"07777777778",
"previous_addresses":[
{
"house_number": "2",
"address1": "Some Street.",
"address3": "London",
"post_code": "N1 1XX",
"from_date":"2014-01-01",
"to_date":"2016-01-01"
}
],
"tos_acceptance": {
"date":"2017-11-23T11:17:05.488037Z",
"ip_address": "1.2.3.4"
}
}
EOM
curl -s -X PATCH "$API_ROOT_URL/customers/10003074/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
On success, the above commands return the profile object:
{
"customer_id": "10000001",
"email": "user1@example.com",
"title":"mr",
"first_name": "FirstName",
"last_name": "LastName",
"contact_number": "07777777778",
"nationality": "GB",
"date_of_birth": "2000-01-01",
"date_joined": "2017-11-23T11:17:05.488037Z",
"address": {
"flat_or_apartment_number": null,
"house_name": null,
"house_number": "1",
"address1": "Some Street.",
"address2": null,
"address3": "London",
"address4": null,
"post_code": "N1 1XX",
"from_date": "2016-01-01"
},
"previous_addresses": [
{
"house_number": "2",
"address1": "Some Street.",
"address3": "London",
"from_date": "2014-01-01",
"post_code": "N1 1XX",
"to_date": "2016-01-01"
}
],
"bank_details": {
"provided": true,
"last_error": ""
},
"investor_type": {
"date_selected": "2017-11-23T14:08:19.107968Z",
"investor_type_id": 1,
"investor_type": "High Net Worth Investor",
"net_investible_assets": "500000",
"net_investible_assets_currency": "GBP",
"annual_income": "100000",
"annual_income_currency": "GBP",
"occupation": "CEO"
},
"user_agreement": {},
"tos_acceptance": {
"date": "2017-11-23T11:17:05.488037Z",
"ip_address": "1.2.3.4"
},
"ifisa_agreement_acceptance": null,
"validation": {
"status": "onboarding",
"can_withdraw": false,
"can_invest_high_yield": false,
"can_invest_perpetuals": false,
"can_invest_special_situations": false,
"next_actions": [
"answer-investor-questionnaire"
],
"can_invest": false,
"aml_check": {
"status": "AML Check Pending",
"passed": false
},
"fields_needed": [],
"documents": {
"proof_of_address": "not-yet-needed",
"photo_id": "not-yet-needed"
},
"document_info":{},
"questionnaire":{
"high-yield": "not-attempted",
"perpetual": "not-attempted",
"signup": "not-attempted",
"smart-interest": "not-attempted",
"special-situation": "not-attempted"
}
}
}
This endpoint is used to retrieve or update data for the specific account. On success, we return the profile object for that user.
Trying to access an account that is not associated with this API key will result in a 403 - Permission Denied.
Available Methods:
- GET: Returns detailed information about an account.
- PUT: Updates a managed user's profile.
- PATCH: Updates specific fields of a managed user's profile.
GET requests
This endpoint retrieves detailed information about an account. Data is returned as a profile object.
PUT requests
This method updates the user's details in their entirety.
PATCH requests
This method updates specific fields in the user's profile.
List investor types
URL: GET /customers/investor_types/
api = requests.get('$API_ROOT_URL/customers/investor_types/', headers=headers)
curl -s "$API_ROOT_URL/customers/investor_types/" \
-H "Authorization: Token $API_KEY" | jq .
Returns a list of investor types as the following JSON:
{
"investor_types":[
{
"id":3,
"identifier": "Sophisticated Investor",
"title":"Sophisticated Investor",
"intro_title":"What is a Sophisticated Investor?",
"intro_content":"<p>Description of this investor type.</p>\r\n",
"main_title":"Sophisticated Investor Statement",
"main_content":"<p>What the investor is agreeing to ...</p>"
},
{
"id":4,
"identifier": "Certified High Net Worth Investor",
"title":"High Net Worth Individual",
"intro_title":"What is a High Net Worth Individual?",
"intro_content":"<p>Description of this investor type.</p>\r\n",
"main_title":"High Net Worth Individual Statement",
"main_content":"<p>What the investor is agreeing to ...</p>"
},
{
"id":5,
"identifier": "Professional Investor",
"title":"Investment Professional",
"intro_title":"What is an Investment Professional?",
"intro_content":"<p>Description of this investor type.</p>\r\n",
"main_title":"Investment Professional Statement",
"main_content":"<p>What the investor is agreeing to ...</p>"
}
]
}
Available Methods:
- GET: Returns investor types and net investible asset bands.
GET request
This endpoint fetches details of the investor categories
The investor_types
contains a list of investor types. Certain types
have more privileges than others, and each type has an associated investor agreement.
Users must select an investor type, provide the appropriate information for that investor type, and agree to the associated investor agreement. See the onboarding section of this document for details.
WiseAlpha reserve the right to contact the client to check that the investor type and band are set correctly.
Change investor type
URL: POST /customers/{}/change_investor_type/
data = {
"investor_type_id": 1,
"net_investible_assets": "500000",
"net_investible_assets_currency": "GBP",
"annual_income": "100000",
"annual_income_currency": "GBP",
"occupation": "CEO",
}
api = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/change_investor_type/',
data=data, headers=headers)
read -r -d '' DATA << EOM
{
"investor_type_id": 1,
"net_investible_assets": "500000",
"net_investible_assets_currency": "GBP",
"annual_income": "100000",
"annual_income_currency": "GBP",
"occupation": "CEO"
}
EOM
curl -s -X POST "$API_ROOT_URL/customers/$CUSTOMER_ID/change_investor_type/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
If the investor type change request is accepted, we return a 200 or 202 return code with a simple status body:
{
"status": "ok"
}
This endpoint is used to set the user's investor type via submitting a Change investor type object. Setting an investor type also implies the user has read and accepted the investor agreement for this investor type. As such, you should have shown the relevant document to the investor before calling this endpoint.
WiseAlpha reserves the right to contact the user to discuss whether the selected investor type is appropriate for their circumstances.
See the Change investor type object documentation for a description of what fields are required for each investor type.
Get questionnaire
URL: GET /customers/{customer_id}/questionnaire/
api = requests.get('$API_ROOT_URL/customers/{customer_id}/questionnaire/',
params={'type': '{questionnaire_type}'}, headers=headers)
curl -s "$API_ROOT_URL/customers/{customer_id}/questionnaire/?type={questionnaire_type}" \
-H "Authorization: Token $API_KEY" | jq .
Returns a questionnaire as the following JSON:
{
"type":"signup",
"help": "help text",
"questions":[
{
"id":1,
"question":"Question 1?",
"answers":[
{
"id":3,
"answer_text":"Answer 1."
},
{
"id":1,
"answer_text":"Answer 2."
}
],
"mimetype": "text/plain",
"question_type": "radio"
},
...
],
"faqs": [
{
"title": "What are Senior Secured bonds ?",
"link": "https://support.wisealpha.com/glossary/senior-secured"
},
{
"title": "What happens when a corporate borrower defaults ?",
"link": "https://support.wisealpha.com/about-wisealpha/what-happens-if-a-borrower-defaults"
},
{
"title": "How does our secondary market operate ?",
"link": "https://support.wisealpha.com/glossary/secondary-market"
},
{
"title": "When will I receive Interest Payments ?",
"link": "https://support.wisealpha.com/payments-and-fees/when-will-i-receive-interest-payments"
},
{
"title": "What is Yield To Maturity ?",
"link": "https://support.wisealpha.com/glossary/yield-to-maturity"
},
{
"title": "What is Current Yield ?",
"link": "https://support.wisealpha.com/glossary/current-yield"
}
],
"user_status": {
"blocked_message": null,
"num_failed_attempts": 0,
"max_num_failed_attempts": 3,
"num_attempts_remaining": 3,
"passed": false
},
"hash": "680b7d32e5f5b39528b46dd0e4051c41"
}
This endpoint fetches details of the questionnaires users must answer before accessing WiseAlpha investments. This is used to make sure the investor understands the nature of the investments and the risks involved.
This endpoint requires a single type
parameter that should be set to one of signup
, high-yield
, special-situation
or perpetual
.
The signup
questionnaire must be answered before the user can invest in the platform. The other questionnaires are for access to
specific WiseAlpha markets and are explained elsewhere.
Additionally the user's status for the questionnaire will be returned.
Returned is a Questionnaire Object
Submit questionnaire results
URL: POST /customers/{customer_id}/upload_questionnaire_results/
data = {
"type": "signup",
"questions_answered": [
{"question_id": 1, "answer_id": 1},
{"question_id": 2, "answer_id": 6},
{"question_id": 3, "answer_id": 7},
{"question_id": 4, "answer_id": 10},
{"question_id": 5, "answer_id": 15},
{"question_id": 7, "answer_text": "This is a free text response"}
]
}
api = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/upload_questionnaire_results/',
data=data, headers=headers)
read -r -d '' DATA << EOM
{
"type": "signup",
"questions_answered": [
{"question_id": 1, "answer_id": 1},
{"question_id": 2, "answer_id": 6},
{"question_id": 3, "answer_id": 7},
{"question_id": 4, "answer_id": 10},
{"question_id": 5, "answer_id": 15},
{"question_id": 7, "answer_text": "This is a free text response"}
]
}
EOM
curl -s -X POST "$API_ROOT_URL/$CUSTOMER_ID/upload_questionnaire_results/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
The questionnaire is returned along with the user status which will indicate pass/fail.
{
"type": "signup",
...
"user_status": {
"blocked_message": null,
"num_failed_attempts": 0,
"max_num_failed_attempts": 3,
"num_attempts_remaining": 3,
"passed": true
}
}
This method is used to upload the user's answers to one of our questionnaires, and check whether the answers are correct. It is not sufficient for the user to answer the questionnaire, they must also answer it correctly. In all cases, the endpoint returns a 200 response, and you should check the response data to see if the questionnaire was answered correctly.
A Quesitonnaire Object is returned which will include the Questionnaire User Status object indicating pass or fail.
Document upload
import requests
import os
import mimetypes
photo_id = os.path.join('/../path_to_docs', 'photo_id.jpg')
with open(photo_id, 'rb') as f:
headers = {'Authorization': 'Token ' + api_token}
headers['Content-Type'] = mimetypes.guess_type(photo_id)[0]
headers['Content-Disposition'] = 'attachment; filename={0}'.format(photo_id)
result = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/upload_photo_id/',
data=f, headers=headers)
address_id = os.path.join('/../path_to_docs', 'address_id.jpg')
with open(address_id, 'rb') as f:
headers = {'Authorization': 'Token ' + api_token}
headers['Content-Type'] = mimetypes.guess_type(address_id)[0]
headers['Content-Disposition'] = 'attachment; filename={0}'.format(address_id)
result = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/upload_proof_of_address/',
data=f, headers=headers)
# Upload photo ID in file $PHOTO_ID
curl -s -X POST "$API_ROOT_URL/customers/$CUSTOMER_ID/upload_photo_id/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: $(file --mime-type -b $PHOTO_ID)" \
-H "Content-Disposition: attachment; filename=$(basename $PHOTO_ID)" \
-d $PHOTO_ID | jq .
# Upload proof of address in file $PROOF_OF_ADDRESS using multipart/form-data
curl -s -X POST "$API_ROOT_URL/customers/$CUSTOMER_ID/upload_proof_of_address/" \
-H "Authorization: Token $API_KEY" \
-F "document=@$PROOF_OF_ADDRESS" | jq .
A successful upload returns the following JSON:
{
"status": "ok"
}
When the AML check fails the user will be asked to upload ID documents to confirm their identity. They will not have full access to their account and the WiseAlpha investments until this formality is completed.
We require 2 proofs of identity:
A government-issued photo ID. (Note that we don't require that the user is a British citizen, so foreign-issued passports and driver's licenses are acceptable.)
A bill or other form of official correspondence dated from within the last 3 months and showing the user's postal address.
Once submitted, these documents are manually verified by the WiseAlpha team, and, if acceptable,
the account will be fully enabled. We will issue a webhook event to inform
you when the check is complete. If a document is deemed unacceptable, the event will contain a
reason for the rejection, the document status will be set to rejected
and the reason for the
rejection will be added to the document_info
section of the validation object.
In this case, you should provide a mechanism for the user to upload a replacement
for the deficient document.
From time to time, we may require that the user upload additional documents, e.g., to prove
the user owns the destination bank account when making withdrawals. In these circumstances,
the ID of the required document will be added to the documents
section of the validation object.
You can use this endpoint to upload the requested document.
Available Methods:
- POST: Submit a document.
You can upload the document either by posting it directly to the HTTP endpoint with an appropriate
Content-Type
and Content-Disposition
, or by embedding it in a multipart/form-data
body type,
containing a single part with name document
and appropriate Content-Type and Content-Disposition
section headers.
POST requests
There is one endpoint for each document type we require:
/customers/{customer_id}/upload_<document_type>/
- Upload a document
where <document_type>
is one of the known document types: photo_id
, proof_of_address
, etc.
Uploaded documents must be in one of the following formats: JPEG, GIF, PNG, PDF or bitmap (BMP).
/customers/{customer_id}/push-notifications-configuration/
## GET request
api = requests.get('$API_ROOT_URL/customers/{customer_id}/push-notifications-configuration/',
params={'type': '{questionnaire_type}'}, headers=headers)
## PUT request
data = {
"configuration": {
"MARKETING:NEW_BOND_AVAILABLE": {
"ENABLED": "ON",
"PERIOD": "DAILY"
}
}
}
api = requests.put('$API_ROOT_URL/customers/{customer_id}/push-notifications-configuration/',
data=data, headers=headers)
## GET request
curl -s "$API_ROOT_URL/customers/{customer_id}/push-notifications-configuration/" \
-H "Authorization: Token $API_KEY" | jq .
## PUT request
read -r -d '' DATA << EOM
{
"configuration": {
"MARKETING:NEW_BOND_AVAILABLE": {
"ENABLED": "ON",
"PERIOD": "DAILY"
}
}
}
EOM
curl -s -X PUT "$API_ROOT_URL/customers/{customer_id}/push-notifications-configuration/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
Returns the customer's push notifications configuration:
{
"configuration": {
"MARKETING:NEW_BOND_AVAILABLE": { "ENABLED": "ON" }
},
"net_configuration": {
"TRANSACTIONS_AND_PAYMENTS:BOND_PAYMENTS": { "ENABLED": "OFF" },
"MARKETING:MARKETING": { "ENABLED": "OFF" },
"MARKETING:NEW_BOND_AVAILABLE": { "ENABLED": "ON" },
"MARKETING:NEWS_AND_UPDATES": { "ENABLED": "OFF", "PERIOD": "WEEKLY" }
}
}
Available Methods:
- GET: Returns the customer's push notification configuration.
- PUT: Sets the customer's push notification configuration.
GET requests
This endpoint fetches the user's push notifications configuration. Push notifications will be scheduled based on this configuration.
PUT requests
This endpoint allows users to edit the push notifications configuration.
/customers/{customer_id}/email-notifications-configuration/
## GET request
api = requests.get('$API_ROOT_URL/customers/{customer_id}/email-notifications-configuration/',
params={'type': '{questionnaire_type}'}, headers=headers)
## PUT request
data = {
"configuration": {
"MARKETING:NEW_BOND_AVAILABLE": {
"ENABLED": "ON",
"PERIOD": "DAILY"
}
}
}
api = requests.put('$API_ROOT_URL/customers/{customer_id}/email-notifications-configuration/',
data=data, headers=headers)
## GET request
curl -s "$API_ROOT_URL/customers/{customer_id}/email-notifications-configuration/" \
-H "Authorization: Token $API_KEY" | jq .
## PUT request
read -r -d '' DATA << EOM
{
"configuration": {
"MARKETING:NEW_BOND_AVAILABLE": {
"ENABLED": "ON",
"PERIOD": "DAILY"
}
}
}
EOM
curl -s -X PUT "$API_ROOT_URL/customers/{customer_id}/email-notifications-configuration/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
Returns the customer's email notifications configuration:
{
"configuration": {
"MARKETING:NEW_BOND_AVAILABLE": { "ENABLED": "OFF" }
},
"net_configuration": {
"TRANSACTIONS_AND_PAYMENTS:BOND_PAYMENTS": { "ENABLED": "ON" },
"MARKETING:MARKETING": { "ENABLED": "ON" },
"MARKETING:NEW_BOND_AVAILABLE": { "ENABLED": "OFF" },
"MARKETING:NEWS_AND_UPDATES": { "ENABLED": "ON", "PERIOD": "WEEKLY" }
}
}
Available Methods:
- GET: Returns the customer's email notification configuration.
- PUT: Sets the customer's email notification configuration.
GET requests
This endpoint fetches the user's email notifications configuration. email notifications will be scheduled based on this configuration.
PUT requests
This endpoint allows users to edit the email notifications configuration.
Push notification device registration
URL: POST /customers/{customer_id}/push-notifications/device/
## POST request
data = {
"deviceId": "DEVICE_ID",
"name": "Friendly name",
"registrationId": "..."
}
api = requests.post('$API_ROOT_URL/customers/{customer_id}/push-notifications/device/',
data=data, headers=headers)
## POST request
read -r -d '' DATA << EOM
{
"deviceId": "DEVICE_ID",
"name": "Friendly name",
"registrationId": "REGIRATION_ID"
}
EOM
curl -s -X POST "$API_ROOT_URL/customers/{customer_id}/push-notifications/device/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
Returns:
HTTP 204 - No Response
Available Methods:
- POST: Registers the device for the user. If the user had previously registered this device with a different registration ID, then the old registration will be replaced with the new one.
Enable/Disable a Push notification device
URL: PATCH /customers/{customer_id}/push-notifications/device/DEVICE_ID/
## PATCH request
data = {
"enabled": false,
}
api = requests.patch('$API_ROOT_URL/customers/{customer_id}/push-notifications/device/DEVICE_ID/',
data=data, headers=headers)
## PATCH request
read -r -d '' DATA << EOM
{
"enabled": false
}
EOM
curl -s -X PATCH "$API_ROOT_URL/customers/{customer_id}/push-notifications/device/DEVICE_ID/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
Returns:
HTTP 204 - No Response
Available Methods:
- PATCH: Enables/Disables the registered push notification device.
Get list of company updates for a user
URL: GET /customers/{customer_id}/company-updates/
Example
GET
request
api = requests.get('$API_ROOT_URL/customers/{customer_id}/company-updates/limit=2&offset=10', headers=headers)
curl -s "$API_ROOT_URL/customers/{customer_id}/company-updates/limit=2&offset=10" \
-H 'Authorization: Token $API_KEY' | jq .
The above command returns JSON structured like this:
{
"count": 31,
"next": "$API_ROOT_URL/customers/{customer_id}/company-updates/?limit=1&offset=1",
"previous": null,
"results": [
{
"id": 25079,
"source": {
"id": 1137,
"name": "Aggredium",
"description": "London Stock Exchange",
"url": "https://www.londonstockexchange.com/",
"image": "https://docs.londonstockexchange.com/sites/default/files/logo.svg"
},
"title": "AA 2021Q2 financials updated",
"description": "Please find the newest AA financials here: [https://aggredium.com/company/AABOND/standardized/?data\\_view=ltm'](https://aggredium.com/company/AABOND/standardized/?data_view=ltm')\n\n ",
"published_time": "2020-09-29T11:15:44Z",
"url": "https://aggredium.com/company/AABOND/standardized/?data_view=ltm'",
"provider": "AGGREDIUM",
"type": "COMPANY_NEWS",
"image": "https://cityfalconproduction.blob.core.windows.net/autotweetmedia/domains/logos/79/small.png",
"category": "financials update",
"priority": "LOW",
"companies": [
{
"company_id": "CO00000019",
"company_name": "The AA",
"industry": "services",
"logo": "/media/company/ab55ba40-dd9c-4ecc-8b2a-23ce05c8b124.png"
}
]
},
...
]
}
This endpoint retrieves a list of company updates linked to the current company. Results are arranged in reverse chronological order.
Optional Query Strings for GET
Name | Description | Data Type |
---|---|---|
limit | limit the number of results | Integer |
offset | offset | Integer |
provider | Name of the (meta data) provider (e.g. CITY_FALCON , AGGREDIUM , WISEALPHA ) |
String-Enum |
type | Type of update (e.g. COMPANY_NEWS , PRESS ) |
String-Enum |
priority | Priority level assigned to the update (e.g. LOW , MEDIUM , HIGH ) |
String-Enum |
companies | Comma separated list of company references | String |
Company Updates Subscription
Get list of user's company updates subscription
This endpoint fetches the user's company updates subscription. The user will be notified of new company updates based on these subscriptions.
URL: GET /customers/{customer_id}/company-updates-subscription/
Example
GET
request
api = requests.get('$API_ROOT_URL/customers/{customer_id}/company-updates-subscription/',
headers=headers)
curl -s "$API_ROOT_URL/customers/{customer_id}/company-updates-subscription/" \
-H "Authorization: Token $API_KEY" | jq .
The above command returns JSON structured like this:
{
"CO00000099": "unsubscribed",
"CO00000109": "subscribed",
"CO00000019": "subscribed"
}
Update user's company updates subscription
This endpoint allows users to edit their company updates subscription.
URL: PATCH /customers/{customer_id}/company-updates-subscription/
Example
PATCH
request
data = {
"companies": {
"CO00000001": "subscribed",
"CO00000002": "unsubscribed",
"CO00000003": "unsubscribed",
...
}
}
api = requests.put('$API_ROOT_URL/customers/{customer_id}/company-updates-subscription/', data=data, headers=headers)
read -r -d '' DATA << EOM
{
"companies": {
"CO00000001": "subscribed",
"CO00000002": "unsubscribed",
"CO00000003": "unsubscribed",
...
}
}
EOM
curl -s -X PATCH "$API_ROOT_URL/customers/{customer_id}/company-updates-subscription/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
The above command returns JSON structured like this:
{
"CO00000099": "unsubscribed",
"CO00000109": "subscribed",
"CO00000019": "subscribed"
}
Accept/Decline user agreement
URL: PUT /customers/{}/
data = {
"user_agreements": {
"client-account-migration": {
"decision": "move_funds"
}
}
}
api = requests.put('$API_ROOT_URL/customers/{customer_id}/', data=data, headers=headers)
read -r -d '' DATA << EOM
{
"user_agreements": {
"client-account-migration": {
"decision": "move_funds"
}
}
}
EOM
curl -s -X PUT "$API_ROOT_URL/customers/{customer_id}/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
Returns the customer profile with decision recorded:
HTTP 200 - Profile object
Available Methods:
- PUT: Accept/Decline the agreement
Unlock a user's account
URL: POST /customers/{customer_id}/unlock-account/
Example
POST
request
api = requests.post('$API_ROOT_URL/customers/{customer_id}/unlock-account/', headers=headers)
curl -s "$API_ROOT_URL/customers/{customer_id}/unlock-account/ \
-H "Authorization: Token $API_KEY" | jq .
The above command returns JSON structured like this:
{
"detail": "User account successfully unlocked."
}
This endpoint is only available to accounts with the superuser
, account_manager
, or
customer_service_agent
role. Sending a request to this endpoint from any other role will result in a
403 error.
This endpoint finds the account associated with the provided customer_id
and unlocks the account
by resetting any failed login attempts. A 404 error will be returned if no account is found.
User Audit Log
URL: GET /audit-logs/
URL: GET /audit-logs/{audit_log_record_id}/
An audit log of user actions is available to be queried. This will contain a detailed list of the user's actions while using the platform, as well as some server side generated events for events like investment payments.
Suported Formats
Name | Description |
---|---|
json |
applicaiton/json, default |
csv |
text/csv |
Suported Ordering
Name | Description |
---|---|
created |
Sort from oldest to newest. |
-created |
Sort from newest to oldest. |
Supported Filtering
Name | Supported Lookups |
---|---|
time |
All datetime lookups supported |
user_id |
Exact match on user account_no |
event_type |
Exact match on event_type (multiple supported) |
action |
Exact match on action (multiple supported) |
platform |
Exact match on platform |
User Audit Log Object
Name | Description | Data Type |
---|---|---|
reference | Audit Log entry reference | Reference |
action | Description of action | String |
user_id | The user the log relates to | Customer ID |
time | The time of the entry | DateTime |
event_type | The event_type that triggered the entry | String-Enum |
platform | The platform generating the user was using | String-Enum |
os_name | String | |
os_version | String | |
ip | IP Address | |
language | String | |
event_properties | Varies by event | Object |
User Onboarding
User's cannot invest in the WiseAlpha platform until they have completed initial validation. The user must:
Provide enough personal information for and pass an Anti Money Laundering (AML) check
Prove they understand the nature of the investments on WiseAlpha by answering a questionnaire
Provide an estimate of the investible assets available to the user. If the user appears to be investing unwisely, WiseAlpha may contact the user to discuss their investment strategy.
Some of this process involves manual review by the WiseAlpha team, or are otherwise done offline. In order to be notified when these offline processes are completed, make sure to register a webhook to be notified when the account status changes.
The Validation Object
"validation":{
"status":"onboarding",
"can_invest":false,
"can_invest_high_yield":false,
"can_invest_perpetuals":false,
"can_invest_special_situations":false,
"can_withdraw":false,
"next_actions":[
"provide-missing-fields",
"select-investor-type"
],
"fields_needed":[
"date_of_birth",
"contact_number",
"address",
"bank_details",
"tos_acceptance",
"tax_residencies"
],
"aml_check":{
"status":"No Check Performed",
"passed":false
},
"documents":{
"proof_of_address":"not-yet-needed",
"photo_id":"not-yet-needed"
},
"document_info":{},
"questionnaire":{
"high-yield": "not-attempted",
"perpetual": "not-attempted",
"signup": "not-attempted",
"smart-interest": "not-attempted",
"special-situation": "not-attempted"
}
}
Whenever you fetch a user's profile object, we return an accompanying validation
object.
Details of the validation object can be found in the validation section. Here, we describe the most important fields in this object, and explain how they can be used to shepherd a user through the Onboarding and AML processes.
The validation status
This field indicates the user's progress through the process. It can have one of the following values:
Name | Description |
---|---|
onboarding | We are still waiting for the user to provide personal information |
invest | The user has completed the AML process and can invest and withdraw. The ability to invest in specific products may still be limited by specific market access. |
The validation can_xxx
fields
These indicate what actions the user is currently capable of doing.
If can_invest
is true, the user can deposit money in WiseAlpha and purchase fractional bonds.
If can_invest_high_yield
is true, the user can purchase higher-risk fractional bonds on the
high-yield marketplace. To enable this, the user must complete the high yield questionnaire.
If can_invest_perpetuals
is true, the user can purchase perpetuals on the perpetual marketplace.
To enable this, the user must complete the perpetuals questionnaire and
be cleared by a member of the WiseAlpha compliance team.
If can_invest_special_situations
is true, the user can purchase higher-risk fractional bonds on the
special situations marketplace. To enable this, the user must complete the special situations
questionnaire and be cleared by a member of the WiseAlpha compliance team.
If can_withdraw
is true, the user can withdraw money from his WiseAlpha account. This is sometimes
set false even though can_invest
is true. There can be a compliance block on the user's account
preventing withdrawals.
The next_actions
field
This field contains a list of next steps you should take to progress the user through the onboarding process. It will contain one or more of the following values:
Name | Description |
---|---|
provide-missing-fields | We are waiting for basic profile information for this user. We list the fields we are still waiting for in the fields_needed field described below. |
select-investor-type | The user hasn't selected an investor type. |
confirm-investor-type | The user has previously selected an investor type, but needs to confirm that they still belong to that category. |
answer-signup-questionnaire | The user hasn't answered the signup questionnaire. |
upload-id-documents | The user needs to upload ID documents before we can progress. |
answer-high-yield-questionnaire | The user hasn't answered the high-yield questionnaire. (Note that this isn't a blocking issue - the user may be able to invest in other investments.) |
upload-supporting-document | The user needs to upload additional documents (e.g., a bank statement) |
The fields_needed
field
This field contains a list of user attributes that still need to be provided. Each entry in this list should correspond to one of the top-level fields in the user's profile object.
The aml_check
field
{
"status":"No Check Performed",
"passed":false
}
This field provides the status and result from the automated AML check. The status field contains one of the following values:
Value | Description |
---|---|
No Check Performed | We haven't yet done an automated check. |
AML Check Pending | An automated AML check is pending. We'll issue a webhook event when the result is available. |
Auto Check Failed | We've done the automated check, and it failed. The user will have to upload ID documents to complete the AML process. |
Auto Check Passed | We've done the automated check, and it passed. The AML process is completed and the user is free to invest. |
ID Documents Required | An event has triggered identity verification. The user will have to upload ID documents. |
ID Documents Provided | The user has uploaded ID documents and is waiting for WiseAlpha staff to verify them. |
ID Documents Verified | The user has uploaded ID documents and they've been verified by WiseAlpha. The AML process is complete and the user is free to invest. |
The passed
field indicates whether the user has successfully completed the AML process.
The documents
field
{
"proof_of_address":"not-yet-needed",
"photo_id":"not-yet-needed"
}
This field is a dictionary whose keys list the documents we require. The documents required for the AML process, namely
photo_id
and proof_of_address
, are always included in this list. From time to time,
additional document types may be added, e.g., we may request a bank statement if we cannot
automatically associate the user's bank account details with the user's identity.
For each document, the value in the dictionary indicates whether the document is needed, and if so, whether it has been provided, and accepted. If a document does not appear in the documents list, then it is not yet needed.
You can upload AML documents at any time, even if they are not currently required. Other documents can only be uploaded when they are required.
Document state | Description |
---|---|
not-yet-needed | We don't need these documents yet. |
required | The AML process is blocked until this document is uploaded. |
provided | The user has provided API documents, though they may still be awaiting review by WiseAlpha. |
accepted | The user's documents have been accepted. |
rejected | The user's documents have been rejected, and the rejection reason has been added to the document_info . |
The document_info
field
{
"proof_of_address": { rejection_reason: "Provided document was too old." }
}
This field provides some extra information to help the user upload the correct documents, e.g., - The reason the document was requested - What specific documents are required - The reason an uploaded document was rejected
The field is a dictionary whose keys list the documents where additional information is available. For each key in the list, the value contains a dictionary with one or more of the following subfields:
subfield | Description |
---|---|
request_reason | Any additional information on why this document was requested. For bank statements this will include details of the bank account being verified. |
rejection_reason | If the document status is 'rejected', the reason for the rejection will be included here. |
The questionnaire
field
{
"high-yield": "not-attempted",
"perpetual": "not-attempted",
"signup": "not-attempted",
"smart-interest": "not-attempted",
"special-situation": "not-attempted"
}
This field lists the questionnaires that are available on the platform. In order to gain access to a given market,
the user must pass the relevant questionnaire. There may be other requirements to access a market so please use
the can_xxx
fields as the authoritative flags for access to markets.
Questionnaire state | Description |
---|---|
not-attempted | The questionnaire has never been submitted by the user.[^reset-questionnaire-attempts] |
passed | The user has attempted the questionnaire and passed it. |
failed | The user has attempted the questionnaire and failed it too many times. |
attempted-N-times | The user has attempted the questionnaire but failed it N times. They haven't yet exceeded the maximum number of failures. |
[^reset-questionnaire-attempts]: Under some circumstances we may reset the user's attempts.
In these cases, the questionnaire state will show not-attempted
as though they never attempted the questionnaire.
Providing Information For The Automated AML Check
## Get investor types and signup questionnaire
curl -s $API_ROOT_URL/investor_types/ \
-H "Authorization: Token $API_KEY" | jq .
curl -s $API_ROOT_URL/questionnaires/?type=signup \
-H "Authorization: Token $API_KEY" | jq .
## Create a user
read -r -d '' DATA << EOM
{
"email": "username@example.com",
"first_name": "FirstName",
"last_name": "LastName"
}
EOM
curl -s -X POST "$API_ROOT_URL/customers/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" > create_result.json
jq . create_result.json
CUSTOMER_ID=`jq -r .customer_id create_result.json`
## Add user's personal details using PUT
read -r -d '' DATA << EOM
{
"customer_id":"$CUSTOMER_ID",
"email":"$USERNAME@example.com",
"first_name":"FirstName",
"last_name":"LastName",
"contact_number":"07777777777",
"nationality":"GB",
"date_of_birth":"2000-01-01",
"date_joined":"2017-11-23T11:17:05.488037Z",
"address":{
"house_number": "1",
"address1": "Some Street.",
"address3": "London",
"post_code": "N1 1XX",
"from_date":"2016-01-01"
},
tax_residencies: [{
"country": "gb",
"tax_identification_number": "QQ123456C",
}],
"previous_addresses":[],
"bank_details":{
"GBP": {
"account_name": "FirstName LastName",
"sort_code":123456,
"account_number":12345678,
"country_code": "gb"
}
}
}
EOM
curl -s -X PUT "$API_ROOT_URL/customers/$CUSTOMER_ID/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
## Set the user's previous_addresses and tos_acceptance using PATCH
read -r -d '' DATA << EOM
{
"previous_addresses":[
{
"house_number": "2",
"address1": "Some Street.",
"address3": "London",
"post_code": "N1 1XX",
"from_date":"2014-01-01",
"to_date":"2016-01-01"
}
],
"tos_acceptance": {
"date":"2017-11-23T11:17:05.488037Z",
"ip_address": "1.2.3.4"
}
}
EOM
curl -s -X PATCH "$API_ROOT_URL/customers/$CUSTOMER_ID/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
## Set investor type
read -r -d '' DATA << EOM
{
"investor_type_id": 1,
"net_investible_assets": "500000",
"net_investible_assets_currency": "GBP",
"annual_income": "100000",
"annual_income_currency": "GBP",
"occupation": "CEO"
}
EOM
curl -s -X POST "$API_ROOT_URL/customers/$CUSTOMER_ID/change_investor_type/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
## Upload signup questionnaire
read -r -d '' DATA << EOM
{
"type": "signup",
"questions_answered": [
{"question_id": 1, "answer_id": 1},
{"question_id": 2, "answer_id": 6},
{"question_id": 3, "answer_id": 7},
{"question_id": 4, "answer_id": 10},
{"question_id": 5, "answer_id": 15},
{"question_id": 7, "answer_id": 20}
]
}
EOM
curl -s -X POST "$API_ROOT_URL/customers/$CUSTOMER_ID/upload_questionnaire_results/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
## Fetch details to check status and next-actions
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/" -H "Authorization: Token $API_KEY" | jq .
Attached is a script that creates a user and provides enough information to initiate the automated AML check process.
Most of the script is devoted to setting the user's personal details - name, email address, telephone number etc. This should be self-explanatory.
Selecting an investor type
Before a customer can invest, it is a regulatory requirement for them to select an investor type and by doing so agree to the investor type agreement. At the same time, the user must give an indication of their net investible assets.
You can fetch a list of investor types and investible assets bands via the
/customers/investor_types/
endpoint.
Investor types should be presented and agreed to by the customer. Here is a example of how this might look:
Each panel on this page comes from one investor type object.
The title
field of the object is used to select the investor type, in this case using a 'tabs' interface.
Within each panel, the intro_title
and intro_content
fields contain the title and HTML-encoded text
used in the top part of the panel to present a friendly description of the investor type. Similarly, the
main_title
and main_content
contain the actual agreement to be presented in the bottom part of the panel.
The investor type content contains dates etc., so should be fetched every time the text is displayed to the user.
Once the user has selected an investor type and provided any required additional information, and clicked an 'I agree' button, you should submit this information via the change_investor_type endpoint, passing the ID of the investor type and any additional information required.
After the user has selected an investor type, the value becomes fixed. Subsequent attempts to change the value results in an investor-type change request that is manually processed by WiseAlpha staff. WiseAlpha reserve the right to contact investors to check that their investor type is correct and that their investment strategy is appropriate with consideration of their experience and available assets.
Answering the questionnaires
Before the user can invest, they must answer a signup
questionnaire to show that they understand
the nature of the investments on WiseAlpha, and the risks involved.
If the investor wants to invest in high yield bonds, then they must answer a second high-yield
questionnaire.
If the investor wants to invest in the perpetual or special situations markets they must answer the special-situation
or
perpetual
respectively. In addition to answering the questionnaire a member of our compliance team will review the
market access request and access will only be granted if the application passes compliance.
You fetch the questionnaire data to display via the questionnaires endpoint. This returns a list of questions and, for each question, a set of possible answers. Each question and answer has a unique ID that is used when submitting the questionnaire responses.
To display the questionnaire to the user, you can present it as illustrated in the attached screenshot.
The questionnaire is fairly short and self-explanatory. The user is free to retry the questionnaire until he answers all questions correctly, however multiple failed attempts will raise a flag and may be investigated by the WiseAlpha team.
To submit a questionnaire response, use the submit questionnaire endpoint, passing the IDs of each question asked and ID of each answer selected as described. We return a list of questions the user answered correctly. The questionnaire is completed when all questions are correct, if a user fails their questionnaire three times. Speak to the WiseAlpha team if you want to include links to the FAQs in your page.
Completing The AML Process and Investing In High-Yield Bonds
## Upload identity documents
curl -s -X POST "$API_ROOT_URL/customers/$CUSTOMER_ID/upload_photo_id/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: $(file --mime-type -b $PHOTO_ID)" \
-H "Content-Disposition: attachment; filename=$(basename $PHOTO_ID)" \
-d $PHOTO_ID | jq .
curl -s -X POST "$API_ROOT_URL/customers/$CUSTOMER_ID/upload_proof_of_address/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: $(file --mime-type -b $PROOF_OF_ADDRESS)" \
-H "Content-Disposition: attachment; filename=$(basename $PROOF_OF_ADDRESS)" \
-d $PROOF_OF_ADDRESS | jq .
## Upload high-yield questionnaire
read -r -d '' DATA << EOM
{
"type": "high-yield",
"questions_answered": [
{"question_id": 15, "answer_id": 36},
{"question_id": 16, "answer_id": 38},
{"question_id": 17, "answer_id": 40},
{"question_id": 18, "answer_id": 41},
{"question_id": 19, "answer_id": 43},
{"question_id": 20, "answer_id": 45},
{"question_id": 21, "answer_id": 48}
]
}
EOM
curl -s -X POST "$API_ROOT_URL/customers/$CUSTOMER_ID/upload_questionnaire_results/" \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
## Fetch details to check status and next-actions
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/" -H "Authorization: Token $API_KEY" | jq .
Once the user has completed the onboarding process, this information is checked by an external reference agency. This check will have one of two outcomes:
- Automatic check passed - The user's validation status is
invest
(and their AML check status is "Auto Check Passed"). - Automatic check failed - The user's validation status is
aml-check-failed
(and their AML check status is "Auto Check Failed"). In this case, the user must upload ID documents before he can invest.
Once ID documents are uploaded, the AML check status becomes "AML Documents Provided", and the documents are queued for manual verification. If this succeeds
the AML check status is set to "AML Documents Verified", the user's status is set to invest
, and the user is free to invest without further restrictions.
Accounts and Portfolio
These endpoints return details of the user's balances, owned investments, and historical transactions on the user's account. This information can be used to generate statements, tax and other reports for the user.
A customer has one of more InvestmentAccounts, all balances and investments belong to one of the customers InvestmentAccounts.
Account Data Types
Performance Summary
Name | Description | Data Type |
---|---|---|
principal | The total amount of principal currently held. | Decimal |
portfolio_value | The estimated value of the products held if sold on the secondary market. This estimate does not include Sale or Cash-out Fees. | Decimal |
gains | This is the difference between the Portfolio Value and Cost of investments, inclusive of any cash payments and paid fees. | Decimal |
sales_fees | The total sales fees paid. | Decimal |
service_fees | The total service fees paid. | Decimal |
accrued_service_fees | The total service fees accrued but not yet paid. | Decimal |
cash_bonus | The total cash bonus earned in the account (e.g. earned through our referral scheme or other promotional offers). | Decimal |
interest_accrued | The amount of interest that has been earned but not yet paid out. | Decimal |
interest_paid | The amount of interest that has been paid. This figure is net of paid Service Fees. | Decimal |
interest_earned | The total amount of interest that has been earned, paid and unpaid. This figure is net of paid Service Fees. | Decimal |
interest_paid_gross | The amount of interest that has been paid. This figure is prior to paying Service Fees. | Decimal |
interest_earned_gross | The total amount of interest that has been earned, paid and unpaid. This figure is prior to paying Service Fees. | Decimal |
projected_interest | The interest expected over the next year. | Decimal |
current_yield | The current yield averaged across all investments. | Decimal |
yield_to_maturity | The current yield to maturity averaged across all investments | Decimal |
interest_earned_pending_payment | Total of interest payments past due, but not yet credited to the account. | Decimal |
count_of_positions | The total number of positions represented in the data, this field is not included when the data represents an individual position. | Integer |
total_gain | The total amount gained from this investment. | Decimal |
Smart Interest
Name | Description | Data Type |
---|---|---|
reference | Smart interest product reference. | Reference ID |
holding_name | The holding name for the product. | String |
series_no | The series number for the product. | String |
maturity | The maturity date for the product. | Date |
currency | The currency of the holding. | Currency |
amount | The amount of principal held. | Decimal |
cash_rate | The rate paid on the principal. | Decimal |
sales_fee_rate | The fee if sold. | Decimal |
total_interest_paid | The total interest paid so far. | Decimal |
Investment Product
Name | Description | Data Type |
---|---|---|
reference | Product reference. | Reference ID |
currency | The currency of the product. | Currency |
reinvest_payments | Should payments (e.g. coupon payments) be reinvested in the product. | Boolean |
product_type | The product type (e.g. fractional_bond , robowise or smart_interest ) |
String-Enum |
detail | Detailed product information. | Product object for fractional_bond products, Smart Interest object for smart_interest products and Robowise account object for robowise . |
annotations | User specific information about the product | User Annotations object |
Account Balance
Name | Description | Data Type |
---|---|---|
amount | Balance amount. | Decimal |
currency | The currency of the balance. | Currency |
Payment Method
Name | Description | Data Type |
---|---|---|
method | One of bank_transfer , open_banking , debit_card or account_transfer . |
String-Enum |
details | Transfer details, vary by method. | Method dependent |
FX Quote
Name | Description | Data Type |
---|---|---|
reference | The quote's unique reference. | Decimal |
created | When the quote was created. | DateTime |
sell_currency | The currency that is being sold. | String |
buy_currency | The currency that is being bought. | String |
sell_amount | The amount of currency that will be sold. | Decimal |
buy_amount | The amount of currency that will be bought. | Decimal |
fee_amount | The fee for the trade, in sell_currency . |
Decimal |
fee_rate | The fee rate the trade (in bps). | Integer |
total_sell_cost | The total cost of the sell, inclusive of the sell_amount and fee_amount . |
Decimal |
rate | The fx rate. | String |
state | The state of the quote, one of transient , awaiting_confirmation , confirmed , errored or expired . |
String-Enum |
limits | Information regarding personal or system wide FX limits if any. | An array of FX Limits objects |
errors | A list of errors that will stop the quote from being able to be confirmed. | An FX Quote Error object |
suggested_buy_amount | In the case of an FX Quote that cannot be filled due to a constraint on the amount able to buy or sell, the API will return a suggested buy_amount that can be used |
Decimal |
FX Limits
Name | Description | Data Type |
---|---|---|
user_limit | The daily user FX limit, defined in GBP. The limit is shared across a user's investment accounts. | Decimal |
user_limit_remaining | The amount remaining from user_limit for the calling user. Resets at midnight in the Europe/London timezone. |
Decimal |
buy_max_liquidity | The current maximum amount of liquidity available in the buy currency. | Decimal |
sell_account_balance | The currency sell account balance (in sell_currency). |
FX Quote Error
Name | Description | Data Type |
---|---|---|
error_type | One of insufficient_sell_balance , insufficient_buy_liquidity , daily_limit_reached or trade_would_exceed_daily_limit . |
String-Enum |
Investment Accounts
URL: /customers/{}/investment-accounts/
To retrieve a list of all investment accounts for a user
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/', headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/" \
-H "Authorization: Token $API_KEY" | jq .
Or to read details of a specific investment account
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID',
headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID" \
-H "Authorization: Token $API_KEY" | jq .
The request returns a list of investment accounts as the following JSON:
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"reference": "INVACC00000001",
"account_type": "individual",
"created": "2000-01-01T00:00:00Z",
"currencies": ["GBP"],
"is_closed": False
}
]
}
If you request details for a single investment account, then we return a single object, rather than a list.
Available Methods:
- GET: Returns information about a customer's investment accounts
This endpoint returns the customer's investment accounts, i.e. a container to hold account balances and investments.
You can request details on a specific investment account by specifying the investment account id in the URL.
The summary contains the following information:
Field | Description | Type |
---|---|---|
reference | The reference ID for this account. | Reference ID |
account_type | The type of this investment account. | String (see below) |
created | When the account was created | DateTime |
currencies | The currencies currently active for this investment account | Array of Strings |
is_closed | Is the account open or closed | Boolean |
Investment accounts can be of the following account types:
Account Type | Description |
---|---|
individual | A standard individual account with no specific restrictions. |
ifisa | An account holding IF ISA investments. Only current UK Tax Residents can open and fund IF ISA accounts, and there is a yearly funding limit of £20,000. |
corporate | An account holding investments on behalf of a corporate entity. |
sipp | An account SIPP investments. |
Creating an Account - Availability
URL: GET /customers/{}/investment-accounts/available/
To retrieve a list of all investment accounts available for creation
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/available/', headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/available/" \
-H "Authorization: Token $API_KEY" | jq .
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"account_type": "individual",
"title": "Euro general investment account",
"description": "Open an individual investment account for access to Euro products",
"currency": "EUR",
"is_transfer": false,
"validation": []
},
{
"account_type": "ifisa",
"title": "IF ISA",
"description": "Open a WiseAlpha Innovative Finance ISA (IF ISA) account",
"currency": "GBP",
"is_transfer": false,
"validation": [
"submit_nino",
"agree_to_ifisa_terms"
]
}
]
}
This endpoint will return an array of the possible accounts that can be created. This might also include adding an additional currency to an existing account.
An array of account availability objects will be returned of the form:
Field | Description | Type |
---|---|---|
account_type | The type of investment account individual or ifisa . |
String-Enum |
title | A title that can be displayed to a user explaining the account. | String |
description | A longer description that can be displayed to the user explaining the account. | String |
currency | The currency that the account will be opened with. If this is not GBP then the account may additionally open with a GBP account. |
String |
is_transfer | Is this a transfer of an account from another provider rather than a fresh opening of an account. Currently initiating account transfers via the API is not supported. | Boolean |
validation | Any pre-requisites that are not yet met before the account creation can take place - see below. | Array of Strings |
The possible entries in the validation list are as follows:
Value | Description |
---|---|
submit_nino |
In order to create an IF ISA account, WiseAlpha must have a record of the user's national insurance number. This can be submitted via the tax residencies field on the customer endpoint. |
agree_to_ifisa_terms |
The use must have agreed to WiseAlpha's IF ISA terms. This can be done through a PATCH or POST to the customer endpoint. |
Creating an Account
URL: POST /customers/{}/investment-accounts/available/action/
api = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/available/action/',
data={'account_type': 'individual', 'is_transfer': false, 'currency': 'EUR'}, headers=headers)
curl -s -X POST "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/available/action/"
-H "Authorization: Token $API_KEY"
-H "Content-Type: application/json"
-d '{"account_type": "individual", "is_transfer": false, "currency": "EUR" }' | jq .
On success, this endpoint returns the new or updated investment account.
{
"reference": "INVACC00004182",
"account_type": "individual",
"created": "2019-10-29T21:32:24.998451Z",
"currencies": [
"EUR",
"GBP"
],
"is_closed": False,
}
To action an availability, post the availability back to this endpoint. If successful the investment account will be sent back.
Investment Account Balance
URL: /customers/{}/investment-accounts/{}/balances/
To read details of the uninvested capital balance for all currencies
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/balances/', headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/balances/" \
-H "Authorization: Token $API_KEY" | jq .
Or to read details of the uninvested capital balance for a single currency (
GBP
in this case)
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/balances/GBP/', headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/balances/GBP/" \
-H "Authorization: Token $API_KEY" | jq .
The request returns a list of balance summaries as the following JSON:
[
{
"currency": "GBP",
"amount": "1681.94"
}
...
]
If you request details for a single currency, then we return a single summary, rather than a list.
Available Methods:
- GET: Returns detailed information about an account.
This endpoint returns an investment account's uninvested capital balance, i.e. the amount of money the investment account has available for purchasing investments. There will be one balance for each currency the investment account supports.
Note that this list is never paginated and the result is always a simple array of JSON objects.
You can request details on a specific account by specifying the currency in the URL.
This endpoint returns Account Balance objects.
Query Available Payment Methods
URL: /customers/{}/investment-accounts/{}/balances/{}/available-payment-methods/
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/balances/$CURRENCY/available-payment-methods/',
headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/balances/$CURRENCY/available-payment-methods/" \
-H "Authorization: Token $API_KEY" | jq .
A list of available payment methods for the account and currency will be returned.
Fund Account
URL: /customers/{}/investment-accounts/{}/balances/{}/fund/
api = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/balances/GBP/fund/',
data={'amount': 1000, 'method': 'bank_transfer'}, headers=headers)
curl -s -X POST "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/balances/GBP/fund/"
-H "Authorization: Token $API_KEY"
-H "Content-Type: application/json"
-d '{"amount": 1000, "method", "bank_transfer" }' | jq .
On success, this method returns bank details to be used to complete the transaction
{
"status": "ok",
"transfer_details": {
"amount": "1000.00",
"currency": "GBP",
"wisealpha_reference": "BNKXFR00000007",
"account_name": "DEVELOPER MODE",
"sort_code": "12-34-56",
"account_number": "123456789",
"bank_name": "Test Bank",
"swift_code": "BARCGB22XXX",
"iban": "GB29RBOS60161331926819",
"bank_reference": "000-000-101"
}
}
Available Methods:
- POST: Initiates a bank transfer. Returns bank details that should be used to complete the transfer.
Field | Description | Type |
---|---|---|
amount | The uninvested funds remaining in this account. | Decimal |
method | The method use to fund the account. Either bank_transfer , open_banking , paysafe_js or debit_card . |
String |
route_to | On completion of the payment route the funds to the given child account, this must refer to a child account or be set to null or omitted. | Reference ID |
card_type | Only required when using method debit_card , must be one of visa_debit , maestro_debit , mastercard_debit or visa_electron_debit . |
Reference ID |
token | Only required when using method paysafe_js , must be a one-time chargeable token retreieved through paysafe.js. |
String |
success_url | Only required when using method open_banking , this will be the url the client is redirected to by the open banking provider on success. |
String |
error_url | Only required when using method open_banking , this will be the url the client is redirected to by the open banking provider on error. |
String |
Funding via Bank Transfer
This method initiates a bank transfer. The bank transfer is completed when the funds in question have been transferred to the given WiseAlpha account using the given bank reference.
The transfer_details
object contains details of the requested transfer.
The wisealpha_reference
is WiseAlpha's reference for this transfer, and will
be included in all subsequent updates on this transfer, in particular in
the event we generate to notify you when the funds have arrived in our system
and been credited to your account.
The remaining fields spell out the bank details to use.
The meaning of each field should be obvious from the field name. Note particularly
the bank_reference
. Users must be sure to include this field when creating the
payment/transfer request with their bank. Getting the bank reference wrong causes
delay as WiseAlpha have to manually reconcile the transaction.
Funding via Open Banking
Calling this method will initial an open banking payment session. The returned object will contain a payment_url
that the client should be redirected to.
Funding via Debit Card
This method intitiates a debit card transaction. A URL to navigate the user to in order to complete the transaction will be returned.
Withdrawing funds from an account
URL: POST /customers/{}/investment-accounts/{}/balances/{}/withdraw/
api = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/balances/GBP/withdraw/',
data={'amount': 1000}, headers=headers)
curl -s -X POST "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/balances/GBP/withdraw/"
-H "Authorization: Token $API_KEY"
-H "Content-Type: application/json"
-d '{"amount": 1000 }' | jq .
On success, this method returns the account balance after the withdrawal.
{
"amount": "1000.00",
"currency": "GBP"
}
This endpoint withdraws funds from the given account to the bank account associated with the account. On success the funds will be debited from the account. This endpoint returns an Account Balance object.
Field | Description | Type |
---|---|---|
amount | The date and time that the transaction occurred. | Decimal |
customer_reference | Optional, the reference to appear on the customers bank statement, this is limited to 12 characters. | String |
Account Transaction
URL: /customers/{}/investment-accounts/{}/balances/{}/transactions/
To get a list of all transactions of a particular currency for a customer's investment account:
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/balances/GBP/transactions/',
headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/balances/$CURRENCY/transactions/" \
-H "Authorization: Token $API_KEY" | jq .
This returns a pagination object containing a list of transactions.
{
"count": 6,
"next": null,
"previous": null,
"results": [
{
"created": "2019-05-10T01:55:36Z",
"reference": "TRANS00999844",
"balance": "100.00",
"amount": "100.00",
"currency": "GBP",
"description": "Deposit",
"type": "Deposit via debit card",
"type_id": "FUNDING_PAYMENT"
},
{
"created": "2019-05-10T04:11:07Z",
"reference": "TRANS00999847",
"balance": "80.00",
"amount": "-20.00",
"currency": "GBP",
"description": "Withdrawal to registered bank account",
"type": "Withdrawal",
"type_id": "WITHDRAWAL"
},
...
]
}
The transaction endpoint does not support fetching a single transaction.
Available Methods:
- GET: Returns a list of transactions for an account.
This method returns a list of all the transactions on the given user's investment account.
The fields in the transaction object are:
Field | Description | Type |
---|---|---|
created | The date and time that the transaction occurred. | DateTime |
reference | A unique reference for this transaction. | Reference ID |
balance | The uninvested funds remaining in this account after the transaction. | Decimal |
amount | The amount the transaction changes the account balance. Negative values correspond to withdrawals, investment purchases etc. | Decimal |
currency | The currency this transaction used. | Currency |
description | A description of the transaction. | String |
type | A description of the transaction type. | String |
type_id | The transaction type. | String-Enum |
Optional Query Strings for GET
Name | Description | Data Type |
---|---|---|
from_date | Filter to return only transactions dated after from_date , including transactions on from_date . Date string format: YYYY-MM-DD. E.g. ?from_date=2022-02-15 |
String |
to_date | Filter to return only transactions dated before to_date , excluding transactions on to_date . Date string format: YYYY-MM-DD. E.g. ?to_date=2022-07-04 |
String |
The from_date
and to_date
query strings can be combined. E.g. ?from_date=2022-02-15&to_date=2022-07-04
Common transaction types:
Type ID | Type | Description |
---|---|---|
FUNDING_PAYMENT |
Deposit via debit card | User has deposited money in his account via debit card. |
BANK_TRANSFER_IN |
Deposit via bank transfer | User has deposited money in his account via bank transfer. |
WITHDRAWAL |
Withdrawal | User has withdrawn money from his account. |
BUY_PRINCIPAL |
Purchase: Principal | User has purchased the principal for a bond |
BUY_INTEREST |
Purchase: Accrued interest | User has purchased the accrued interest for a bond |
BUY_SETASIDE |
Buy setaside | User has set aside money for the purchase of a bond |
SALE_PRINCIPAL |
Sale: Principal | User has purchased the principal for a bond |
SALE_INTEREST |
Sale: Accrued Interest | User has sold the accrued interest for a bond |
FEE_SERVICE_PAID |
Service Fee | User has paid the service fee accumulated while holding the bond |
FEE_SALES_PAID |
Secondary Sales Fee | User has paid the sales fee when selling a bond |
MARKETING_FEE_CREDIT_RECEIVED |
Fees credited | Fees have been returned to the user as part of an incentive scheme |
INTEREST_PAYMENT_RECEIVED |
Payment of interest | User has been paid a coupon |
CAPITAL_REPAYMENT_RECEIVED |
Repayment: Principal | User has been paid the bond principal as part of a repayment |
INTEREST_REPAYMENT_RECEIVED |
Repayment: Interest | User has been paid the final coupon as part of a repayment. |
`` |
Account Withdrawals
URL: /customers/{}/investment-accounts/{}/balances/{}/withdrawals/
To get a list of all the withdrawal requests made for a particular currency for a customer's investment account:
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/balances/GBP/withdrawals/',
headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/balances/GBP/withdrawals/" \
-H "Authorization: Token $API_KEY" | jq .
This returns a pagination object containing a list of withdrawal requests.
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"created": "2019-05-10T01:55:36Z",
"reference": "WR00999844",
"state": "open",
"amount": "100.00",
"amount_currency": "GBP",
"scheduled_on": null,
"paid_on": null
}
...
]
}
Available Methods:
- GET: Returns a list of withdrawal requests for an account.
This method returns a list of all the withdrawal requests on the given user's investment account.
The fields in the transaction object are:
Field | Description | Type |
---|---|---|
created | The date and time that the withdrawal was requested. | DateTime |
reference | A unique reference for this withdrawal. | Reference ID |
state | The state of the withdrawal. | Decimal |
amount | The amount of the withdrawal. | Decimal |
currency | The currency of the withdrawal. | Currency |
scheduled_on | The date and time that the withdrawal was issued from WiseAlpha's client money account. | DateTime |
paid_on | The date and time the transaction was verified in WiseAlpha's client money account transaction feed. | DateTime |
URL: /customers/{}/investment-accounts/{}/balances/{}/withdrawals/{}/
An individual withdrawal can be queried by specifiying the withdrawal reference.
Debit Notes
GET /customers/{}/investment-accounts/{}/balances/{}/debit-notes/
GET /customers/{}/investment-accounts/{}/balances/{}/debit-notes/{}/
To get a list of all the debit notes issued for a particular currency for a customer's investment account:
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/balances/GBP/debit-notes/',
headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/balances/GBP/debit-notes/" \
-H "Authorization: Token $API_KEY" | jq .
This returns a pagination object containing a list of debit-notes.
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"created": "2019-05-10T01:55:36Z",
"reference": "WR00999844",
"state": "open",
"amount": "100.00",
"amount_currency": "GBP",
"scheduled_on": null,
"paid_on": null
}
...
]
}
Available Methods:
- GET: Returns a list of withdrawal requests for an account.
This method returns a list of all the withdrawal requests on the given user's investment account.
The fields in the transaction object are:
Field | Description | Type |
---|---|---|
created | The date and time that the withdrawal was requested. | DateTime |
reference | A unique reference for this withdrawal. | Reference ID |
state | The state of the withdrawal. | Decimal |
amount | The amount of the withdrawal. | Decimal |
currency | The currency of the withdrawal. | Currency |
scheduled_on | The date and time that the withdrawal was issued from WiseAlpha's client money account. | DateTime |
paid_on | The date and time the transaction was verified in WiseAlpha's client money account transaction feed. | DateTime |
URL: /customers/{}/investment-accounts/{}/balances/{}/withdrawals/{}/
An individual debit note can be queried by specifiying the debit note reference.
FX Quotes
URL: GET /customers/{}/investment-accounts/{}/fx-quotes/
To return a list of all FX quotes generated for a given investment account:
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/fx-quotes/', headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/fx-quotes/" \
-H "Authorization: Token $API_KEY" | jq .
This method returns a list of all the FX Quotes generated for a given investment account.
Create an FX Quote
URL: POST /customers/{}/investment-accounts/{}/fx-quotes/
To create an FX Quote, the below fields must be provided. The quote can be created in order to sell or buy a specific amount.
Field | Description | Type |
---|---|---|
sell_currency | The currency to sell. | Currency |
buy_currency | The currency to buy. | Currency |
sell_amount | The amount to sell, if this field is specified, buy_amount should not be. |
Decimal |
buy_amount | The amount to buy, if this field is specified, sell_amount should not be. |
Currency |
transient | Optional, set to true to create an indicative quote to be used for display purpuses only, the quote will not exist on the server and cannot be confirmed. | Boolean |
An FX Quote object will be returned as a result of the call. There are constraints that may prevent an FX Quote from being filled, either the user or the system may have reached a daily limit for trading. Most users will have a limit of GBP10,000 convertable in given day, with the period measured as the amount traded the 24 hours of the UK day.
When a quote is submitted that can't be filled (e.g. not enough buy currency liquidity) the system will return a suggested_buy_amount
that will be able to be traded.
Confirm FX Quote
URL: POST /customers/{}/investment-accounts/{}/fx-quotes/{}/confirm
Confim an FX quote
Use this method to confirm and executed a quote. If it can be filled it will execute and return the quote with the confirmed
state, if not it will be returned with an error message
explaining the reason why. E.g. the counterparty account may not currently have sufficient balance to complete the trade.
api = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/fx-quotes/$QUOTE_REFERENCE/confirm/', headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/fx-quotes/$QUOTE_REFERENCE/confirm/" \
-H "Authorization: Token $API_KEY" \
-d '{}'| jq .
Account Products
URL: GET /customers/{}/investment-accounts/{}/products/
To read details of all the investments the customer has purchased in a given investment account:
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/products/', headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/products/" \
-H "Authorization: Token $API_KEY"
Or to read details of a specific investment:
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/products/INVMKT00000001/', headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/products/INVMKT00000001/" \
-H "Authorization: Token $API_KEY" | jq .
The request returns a list of investments as the following JSON:
json [ ... ]
This method returns a list of all the investments the user owns in a given investment account, or has owned in the past.
The fields returned in each investment object are:
Field | Description | Type |
---|---|---|
reference | The product identifier for the underlying investment | Reference ID |
product | Investment product data | Investment Product object |
open | The open position data if applicable. | Performance Summary object |
closed | The closed position data if applicable. | Performance Summary object |
A closed holding represents a position that the account held in the past. I.e. if an account owns 1000 of a product, then sells half of the product, the gain/loss from the sold half will appear in the closed position.
This endpoint supports inclusions and exclusions.
Available Expansions
Name | Description |
---|---|
product |
Expand the product information |
product__detail |
Expand the product detail information |
product__detail__* |
All normal product expansions can be used from here, e.g. product__detail__cashflows |
product__annotations |
Get user annotations on the product. |
Optional Query Strings for GET
Name | Description | Data Type |
---|---|---|
currencies | Filter to return only products in certain currencies. E.g. ?currencies=GBP,EUR |
String |
exclude_fractional_bond_product_detail | If expanding with product__detail , use this to exclude fractional_bond products from returning detail if you have already retrieved that data from a different source. |
String |
Updating Account Products
URL: PATCH /customers/{}/investment-accounts/{}/products/{}/
You can update the reinvest_payments
field of the investment product via the above endpoint.
api = requests.patch('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/products/INVMKT00000001/',
headers=headers,
data={"product": {"reinvest_payments": True}})
curl -X PATCH \
-s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/products/INVMKT00000001/" \
-H "Authorization: Token $API_KEY" \
-d '{"product": {"reinvest_payments": true}}'| jq .
Account Product Transfer
URL: POST /customers/{}/investment-accounts/{}/products/{}/transfer/
To transfer a bond into a sub-account:
api = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/products/INVMKT00000001/transfer/',
headers=headers,
data={"account": "$SUB_ACCOUNT_ID"})
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/products/INVMKT00000001/transfer/" \
-H "Authorization: Token $API_KEY" \
-d '{"account": "$SUB_ACCOUNT_ID"}'| jq .
Investments from a parent account can be transferred into child accounts. It's important to remember that child have specific purposes like robowise, so after transferring the bond may be sold in part or in whole depending on the paramters of the child account.
Field | Description | Type |
---|---|---|
account | The account reference to transfer ownership to. | Reference ID |
Account Portfolio Summary
URL: /customers/{}/investment-accounts/{}/products/summary/
To fetch a summary of an investment account's investments for all currencies
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/products/summary/', headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/products/summary/" \
-H "Authorization: Token $API_KEY" | jq .
To fetch a summary of an investment account's investments for a single currency (
GBP
in this case)
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/products/summary/GBP/', headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/products/summary/GBP/" \
-H "Authorization: Token $API_KEY" | jq .
The request returns a list of account summaries as the following JSON:
[
{
"currency": "GBP",
"has_equity": true,
"has_robowise": true,
"summaries": {
"all": {
...
},
"open": {
...
}
}
}
...
]
If you request details for a single currency, then we return a single summary, rather than a list.
Available Methods:
- GET: Returns detailed information about an account.
This endpoint produces a summary of the investment account's investments. The investment account will have one summary for each currency WiseAlpha supports.
Note that this list is never paginated and the result is always a simple array of JSON objects.
You can request details for a specific currency by specifying the currency in the URL.
The account object is created the first time the account is funded, and these summaries are unavailable until that time.
The summary contains the following information:
Field | Description | Type |
---|---|---|
currency | The currency used for this account. | Currency |
has_equity | The investment account has some equity investments | Boolean |
has_robowise | The investment account has a robowise subaccount | Boolean |
summaries | The number of investments the investment account holds. | Object |
summaries.all | The performance summary across the lifetime of the investment account. | Performance Summary |
summaries.open | The performance summary for the open investments. | Performance Summary |
Account Activity
URL: /customers/{}/investment-accounts/{}/activity/{}/
To fetch an investment account's activity feed
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/activity/$CURRENCY/', headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/activity/$CURRENCY/" \
-H "Authorization: Token $API_KEY" | jq .
The request returns a list of account summaries as the following JSON:
[
{
"group": "August 2016",
"amount": "105.8500",
"currency": "GBP",
"date_description": "07 Aug 2016",
"created": "2016-08-07T05:21:40.325885Z",
"description": "Bought <a href='https://www.wisealpha.com/market/corporate-bond/vue-entertainment/12/XS0953085114'>Vue Entertainment</a>",
"item_logo": "https://d1x9604lsph6r7.cloudfront.net/media/cache/56/57/5657119b244045cf49026f07ea5737b2.png",
"activity_type": "past",
"transaction_type": "buy"
},
{
"group": "February 2017",
"amount": "3.9300",
"currency": "GBP",
"date_description": "Interest paid on 03 Feb 2017",
"created": "2017-02-03T13:18:12.534450Z",
"description": "Payment from <a href='https://www.wisealpha.com/market/corporate-bond/vue-entertainment/12/XS0953085114'>Vue Entertainment</a>",
"item_logo": "https://d1x9604lsph6r7.cloudfront.net/media/cache/56/57/5657119b244045cf49026f07ea5737b2.png",
"activity_type": "past",
"transaction_type": "payment"
},
...
{
"group": "August 2055",
"amount": "8.29",
"currency": "GBP",
"date_description": "Interest due on 12 Aug 2055",
"created": "2055-08-12T00:00:00Z",
"description": "Payment from <a href=\"https://www.wisealpha.com/market/corporate-bond/vodafone/84/XS1472483772\">Vodafone</a>",
"item_logo": "https://d1x9604lsph6r7.cloudfront.net/media/cache/e9/db/e9db7946013f482691387202a5cdd924.png",
"activity_type": "future",
"transaction_type": "payment"
},
{
"group": "August 2056",
"amount": "284.65",
"currency": "GBP",
"date_description": "Principal and Interest due on 12 Aug 2056",
"created": "2056-08-12T00:00:00Z",
"description": "Payment from <a href=\"https://www.wisealpha.com/market/corporate-bond/vodafone/84/XS1472483772\">Vodafone</a>",
"item_logo": "https://d1x9604lsph6r7.cloudfront.net/media/cache/e9/db/e9db7946013f482691387202a5cdd924.png",
"activity_type": "future",
"transaction_type": "payment"
}
]
Available Methods:
- GET: Returns an activity feed for a given investment account and currency
This endpoint gives historical and future activity for a given investment account and currency. The activity includes interest and principal repayments, completed buys and completed sells. To see how this might like see the below example from the WiseAlpha web app with the data based around early November 2019.
This endpoint returns an unpaged array of activity feed items as per below:
Name | Description | Data Type |
---|---|---|
group | The month and year of the activity, e.g. February 1981. | String |
amount | The amount of the activity transaction. | Decimal |
currency | The currency of the activity transaction. | String |
date_description | A should description of the date of the activity. | String |
created | The datetime when the activity was created. | DateTime |
description | A short description of the activity. The description may include a link to the product details page on https://www.wisealpha.com if one is available. | String |
item_logo | When the activity relates to a bond it will be the logo of the company that the activity relates to, or an icon representing the activity. It may also be one the value smart_interest in which case no logo is provided. |
String |
activity_type | Either future or past . |
String-Enum |
transaction_type | One of payment , buy , sell or cash-movement . |
String-Enum |
Investment Transactions
URL: /customers/{}/investment-accounts/{}/products/{}/transactions/
To read details of all the transactions made for a given investment:
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/products/INVMKT00000001/transactions/',
headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/products/INVMKT00000001/transactions/" \
-H "Authorization: Token $API_KEY" | jq .
Or to read details of a specific transaction:
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/products/INVMKT00000001/transactions/INVTR00000001/',
headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/products/INVMKT00000001/transactions/INVTR00000001/" \
-H "Authorization: Token $API_KEY" | jq .
The request returns a list of investments as the following JSON:
json [ ... ]
Available Methods:
- GET: Returns detailed information about an account.
This method returns a list of all the investment account's transactions - purchases, payouts, reinvestments etc. - on this investment.
Supported Ordering Fields
Field Name |
---|
created |
Buy Orders
URL: /customers/{}/investment-accounts/{}/buy-orders/
To get a list of all open buy orders for the given investment account.
api = requests.get('$API_ROOT_URL/customers/investment-accounts/$INVESTMENT_ACCOUNT_ID/$CUSTOMER_ID/buy-orders/',
headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/buy-orders/" \
-H "Authorization: Token $API_KEY" | jq .
Or to read details of a specific buy order:
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/buy-orders/MKTBUY00000001/',
headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/buy-orders/MKTBUY00000001/" \
-H "Authorization: Token $API_KEY" | jq .
The list request returns a list of buy orders as the following JSON:
{
"count":2,
"next":null,
"previous":null,
"results":[
{
"id":"MKTBUY00000001",
"original_id":"MKTBUY00000001",
"product_id":"INVMKT00000001",
"type":"gross",
"state":"open",
"currency":"GBP",
"amount":"100.00",
"principal":null,
"my_bid":"100.0000",
"market_price":"100.0000",
"created":"2017-12-20T12:35:31.390342Z",
"settlement_date": null
},
{
"id":"MKTBUY00000002",
"original_id":"MKTBUY00000002",
"product_id":"INVMKT00000002",
"type":"principal",
"state":"pending_settlement",
"currency":"GBP",
"amount":"120.02",
"principal":"200.00",
"my_bid":"50.0125",
"market_price":"50.0125",
"created":"2017-12-20T12:35:31.403366Z",
"settlement_date":"2017-12-25"
}
]
}
This method returns a list of all buy orders that the customer has placed through a given investment account on the market that haven't yet been completed.
You can also get details of a specific buy order by appending the order ID as shown.
Each buy order object contains the following fields:
Name | Description | Data Type |
---|---|---|
id | The ID of the buy order. This can be used in subsequent cancel and confirm requests | Reference ID |
original_id | The ID of the buy order when the buy was first issued. | Reference ID |
product_id | The ID of the investment being purchased | Reference ID |
type | The order type: 'gross' or 'principal' as described in the market section | String |
state | The state of the order - see below | String |
currency | The currency used to complete the order | String |
amount | The amount this investment will cost | Decimal |
principal | For type = principal orders, this is the amount of principal being purchased |
Decimal |
market_price | The price per unit of principal to use for this purchase | Decimal |
my_bid | The price this order is seeking. If this is different from current_buy_price , the order will need to be confirmed |
Decimal |
created | When this order was created | DateTime |
settlement_date | When this order settles (null if settlement is unknown) |
DateTime |
Open orders can be in one of the following states:
State | Description | |
---|---|---|
open | The order is waiting to be matched against a sell | |
confirm | Prices have changed since the order was made. It will need to be confirmed (see below) | |
pending_settlement | The order has executed and will settle on settlement_date |
Optional Query Parameters
Name | Description | Data Type |
---|---|---|
currencies | Filter to return only products in certain currencies. E.g. ?currencies=GBP,EUR |
String |
Sell Orders
URL: /customers/{}/investment-accounts/{}/sell-orders/
To get a list of all open sell orders for the given investment account.
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/sell-orders/',
headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/sell-orders/" \
-H "Authorization: Token $API_KEY" | jq .
Or to read details of a specific sell order:
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/sell-orders/MKTSELL00000001/',
headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/sell-orders/MKTSELL00000001/" \
-H "Authorization: Token $API_KEY" | jq .
The list request returns a list of sell orders as the following JSON:
{
"count":1,
"next":null,
"previous":null,
"results":[
{
"id":"MKTSELL00000001",
"original_id":"MKTSELL00000001",
"product_id":"INVMKT00000004",
"state":"open",
"currency":"GBP",
"amount":"100.00",
"my_ask":"50.0000",
"market_price":"50.0000",
"created":"2017-12-20T13:50:19.839640Z"
}
]
}
This method returns a list of all sell orders that the customer has placed through a given investment account on the market that haven't yet been completed.
You can also get details of a specific sell order by appending the order ID as shown.
Each sell order object contains the following fields:
Name | Description | Data Type |
---|---|---|
id | The ID of the sell order. This can be used in subsequent cancel and confirm requests | Reference ID |
original_id | The ID of the sell order when the sell was first issued. | Reference ID |
product_id | The ID of the investment being sold | Reference ID |
state | The state of the order - see below | String |
currency | The currency used to complete the order | String |
amount | The amount this investment will cost | Decimal |
market_price | The price per unit of principal to use for this purchase | Decimal |
my_ask | The price this order is seeking. If this is different from current_sell_price , the order will need to be confirmed |
Decimal |
created | When this order was created | DateTime |
Open orders can be in one of the following states:
State | Description |
---|---|
open | The order is waiting to be matched against a sell |
confirm | Prices have changed since the order was made. It will need to be confirmed (see below) |
This method returns a list of all sell orders that the customer has placed on the market that haven't yet been completed.
You can also get details of a specific sell order by appending the order ID as shown.
'id' vs 'original_id'
When an order is partially filled - which may happen if there is only a limited amount of the product on the market, or if the next matched counterparty only has/wants a small amount of the product - we create a new order for the remainder.
Similarly, when an order is confirmed, we create a new order at the new price, and archive the original.
The id
field is the ID of the current open order for that user and product. This ID is useful
if you need to discuss the order with the WiseAlpha team.
The original_id
is the ID of the order when the buy or sell request was first issued. If you want to
correlate orders with the original request, for example, to keep the customer informed of its
progress, then you should use the original_id
to do so.
Optional Query Parameters
Name | Description | Data Type |
---|---|---|
currencies | Filter to return only products in certain currencies. E.g. ?currencies=GBP,EUR |
String |
Order Actions
URL: /customers/{}/investment-accounts/{}/buy-orders/{}/action/
URL: /customers/{}/investment-accounts/{}/sell-orders/{}/action/
To confirm an order:
api = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/sell-orders/MKTSELL00000001/action/',
headers=headers,
data={"action": "confirm"})
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/sell-orders/investment-accounts/$INVESTMENT_ACCOUNT_ID/sell-orders/MKTSELL00000001/action/" \
-H "Authorization: Token $API_KEY" \
-d '{"action": "confirm"}'| jq .
To cancel an order
api = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/sell-orders/MKTSELL00000001/action/',
headers=headers,
data={"action": "cancel"})
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/sell-orders/MKTSELL00000001/action/" \
-H "Authorization: Token $API_KEY" \
-d '{"action": "cancel"}'| jq .
In both cases, action returns HTTP return code 200 on success.
The user can use this entrypoint to manage his open orders.
If the price of an investment changes substantially before the order is completed,
then the WiseAlpha platform raises an -order.price-change
event and puts the order
into the confirm
state. In this state, the order will not be filled until the customer
has confirmed that they want to continue.
If the customer decides to continue, they should issue a confirm
action as shown.
This will create a new order based on the old order, but using the new price.
Alternatively, if the customer does not want to continue, (or if the user has changed
his mind about orders in the open
state), they should issue a cancel
action as
shown. This will remove the order from the market.
Robowise Portfolios
Robowise is an automatic portfolio management tool where users can configure a robowise account to target their investments based on a number of parameters and have robowise diversify their portfolio under the configured constraints. For a marketing page explaining the feature to users see here. Robowise trades made to diversify the porfolio will always be 0% fee trades.
Each investment account that supports robowise can have multiple robowise sub-accounts configured that live within the parent account. Currently robowise is only supported for GBP
investment accounts.
The behaviour and description of robowise risk profiles in this section is centered around the risk profiles published and maintained by WiseAlpha. Concepts like robowise risk categories and robowise weightings are generally not used for custom profiles.
Robowise Types
Robowise Risk Categories
Name | Description |
---|---|
medium | Medium risk bond |
high | High risk bond |
not candidate | This bond is not a candidate for inclusion in a robowise portfolio |
hold | This bond is not a candidate for inclusion in a robowise portfolio, but if currently held keep it. |
Robowise Risk Profile
A robowise risk profile maps the broad split of investments that robowise will make with regard to the risk of investments.
Field | Description | Type |
---|---|---|
reference | Profile ID | Reference ID |
label | The name of the profile, e.g. balanced . |
String |
projected_return | The projected return for portfolios using this profile with the default inclusions and exclusions. | Decimal |
weightings | The split between various risk categories. | Robowise Weighting object |
attributes | The base attributes for this risk profile | Robowise Attributes object |
description | A description of the profile. | String |
legacy | True if this is a legacy (deprecated) profile and shouldn't be used in new or updated profiles. | Boolean |
Robowise Weighting
The sum of all fields in the weighting object should add up to 1. A fields particular value indicates how much out of a given risk category robowise will try to hold. So a weighting of .5 indicates robowise will aim to hold 50% of it's holidings in a given risk category.
Field | Description | Type |
---|---|---|
medium | The weighting for medium risk bonds | Float |
high | The weighting for high risk bonds | Float |
Robowise Attributes
Robowise attributes is a summary of the yield, available bonds and calculated yield for a given combination of a Robowise Profile with a set of industry and company exclusions. If run on the base profile then calculated_yield
will equal projected_return
.
Field | Description | Type |
---|---|---|
bond_count | The number of bonds that are candidates for inclusion | Integer |
calculated_yield | The calcualted yield for the returned bonds | Decimal |
candidate_bonds | All the bonds that can be considered for inclusion. | Robowise Bond Summary object Array |
Robowise Bond Summary
Field | Description | Type |
---|---|---|
product_id | The bond's product id. | Reference ID |
company_id | The company for the bond. | Reference ID |
risk_category | The bond's risk category | Robowise Risk Category |
coupon | The bond's coupon | Decimal |
yield | The bond's current yield | Decimal |
weight | The amount of this bond that robowise will attempt to hold as part of this portfolio. | Decimal |
liquidity | The current amount of liquidity available on the market for the bond. | Decimal |
Robowise Company Summary
Field | Description | Type |
---|---|---|
company_id | Company ID. | Reference ID |
company_name | The name of the company. | String |
industry | The key for the primary industry for the company. | String |
Robowise Industry Summary
Field | Description | Type |
---|---|---|
key | The industry key. | String |
name | A descriptive label for the industry. | String |
Robowise Profile Modifiers
Field | Description | Type |
---|---|---|
excluded_industries | An array of industry keys to exclude from the robowise profile. | String Array |
excluded_companies | An array of companies to exclude from the robowise profile. | Reference ID Array |
Robowise Parameters
Field | Description | Type |
---|---|---|
currency | The currency for the portfolio | Currency |
risk_profile | The risk profile the account is running under. | Robowise risk profile object - ignored on PUT/POST |
risk_profile_id | The risk profile id the account is running under. | Reference ID |
profile_modifiers | Modifiers for the selected risk profile. | Robowise profile modifiers object |
reinvest_payments | Whether payments from the profile holdings should be kept and reinvested or paid out into the parent account's wallet. | Boolean |
Robowise Withdrawal Behaviour
Field | Description | Type |
---|---|---|
type | Either all , some or none . |
String-Enum |
amount | The amount of money to withdraw back into the parent account. | Decimal |
Robowise Account Metadata
Field | Description | Type |
---|---|---|
industry_count | The number of industries the profile currently has investments in. | Integer |
Robowise Ideal Holding
Field | Description | Type |
---|---|---|
product_id | ID of the investment product robowise is considering. | String |
company_id | ID of the company for this investment. | String |
industry | The industry that the company operates in. | String |
ideal | The amount of this investment Robowise would like to hold. | Decimal |
wanted | The amount robowise aims to hold after applying real-world constraints (such as minimum investment size.) | Decimal |
held | The amount robowise is currently holding. | Decimal |
to_acquire | The amount robowise is plannint to buy (or sell if this value is negative.) | Decimal |
reason | A hint as to the reason behind Robowise's decision | String |
performance | The performance of this product in the portfolio. | Account product object |
Robowise Status
Field | Description | Type |
---|---|---|
state | A Robowise Account State. | String-Enum |
description | A short human description of the status. | String |
Robowise Account State
State | Description |
---|---|
opening |
The account has been created, but does not have enough funds to start invested (min GBP/EUR 90) |
open |
The account is open and is being actively managed by robowise |
closing |
The account is in the process of being closed, it will not make any new purchases. |
closed |
The account has been closed and no longer has any holdings. It can still be accessed for reporting purpose. |
Robowise Closure Request
Field | Description | Type |
---|---|---|
closure_type | A Robowise Closure Type. | String-Enum |
Robowise Closure Type
Type | Description |
---|---|
transfer_to_parent |
Close the account by transferring all holdings to the parent account. |
liquidate |
Close the account by liquidating all holdings and transferring the cash to the parent account. |
Robowise Account
Field | Description | Type |
---|---|---|
name | A name for the account. | String |
reference | The reference for the robowise profile. | Reference ID |
created | When the account was created | Datetime |
parameters | The parameters controlling the behaviour of this robowise profile. | Robowise parameters object |
status | The current status of this account | Robowise status object |
withdrawal_behaviour | Returns the current withdrawal behaviour set for the account. This field is ignored on update, see Withdraw cash from a Robowise Portfolio for information on how to withdraw cash from a robowise portfolio back into the parent account. | Robowise Withdrawal Behaviour object |
metadata | Additional account metadata | Robowise Account Metadata |
performance | Returns the current and historical performance of the portfolio, not included by default, but is available as an expansion. | Performance Summary object |
balance | Returns the cash balance available to the robowise account, not included by default, but is available as an expansion. | Account Balance object |
ideals | Robowise's investment strategy for each investment, not included by default, but is available as an expansion. | Array of Robowise Ideal Holding objects |
Robowise Withdrawal Request
Field | Description | Type |
---|---|---|
created | The date and time that the robowise withdrawal was requested. | DateTime |
closed_on | The date and time that the robowise withdrawal was either completed or cancelled. | DateTime |
reference | A unique reference for this robowise withdrawal request. | Reference ID |
state | One of queued , processing , completed or cancelled |
String-Enum |
amount_requested | The target for the withdrawal. | Decimal |
amount_processed | The amount currently processed for the withdrawal. | Decimal |
on_complete | The action to take on complete if any. | Object |
Robowise Rebalance
Field | Description | Type |
---|---|---|
created_by_schedule | The schedule that triggered this rebalance. | Reference ID |
created_by_user | The use that triggered this rebalance. | Minimal User Data Type |
created_on | The date and time this rebalance was created. | DateTime |
executed_on | The date and time this rebalance was executed. | DateTime |
Get Robowise Configuration Data
URL: /robowise/{currency}/configuration-data/
Available Methods:
- GET: Return the data needed to set-up or update a robowise profile in a given currency
Parameters:
Field | Description | Type |
---|---|---|
risk_profile_id | The current risk profile in use, providing this will make sure it's returned even if the profile itself has since been marked as inactive. | Reference ID |
The fields returned are:
Field | Description | Type |
---|---|---|
companies | An array of the companies whose bond's are available to invest in under robowise. | Robowise company summary object |
industries | An array of industries available to invest in. | Robowise industry summary object |
risk_profiles | An array of robowise risk profiles | Robowise risk profile object |
suggested_names | An array of suggested portfolio names, this will be filtered by removing any names already used by the calling user. | String Array |
The request returns the data needed to create and update robowise profiles:
{
"companies": [
{
"company_id": "CO00000034",
"company_name": "AMC ",
"industry": "entertainment_media_broadcasting"
},
...
{
"company_id": "CO00000057",
"company_name": "Yell",
"industry": "entertainment_media_broadcasting"
}
],
"industries": [
{
"key": "entertainment_media_broadcasting",
"label": "Entertainment, Media & Broadcasting"
},
...
{
"key": "travel",
"label": "Travel"
}
],
"risk_profiles": [
{
"reference": "RWRP00000002",
"label": "Balanced",
"projected_return": "5.79",
"weightings": {
"high": 0,
"medium": 1.0,
},
"attributes": {
"candidate_loans": [
{
"product_id": "INVMKT00000011",
"company_id": "CO00000011",
"risk_category": "medium",
"coupon": "6.0000",
"weight": "0.02631579",
"yield": "3.7000"
},
...
{
"product_id": "INVMPE00000088",
"company_id": "CO00000067",
"risk_category": "medium",
"coupon": "5.1250",
"weight": "0.02631579",
"yield": "6.8000"
}
],
"calculated_yield": 5.79,
"bond_count": 38
},
"description": "100% weighting to investments on the Main Market (Senior Secured and Senior Unsecured) with no high yield market exposure."
},
{
"reference": "RWRP00000003",
"label": "Adventurous",
"projected_return": "7.85",
"weightings": {
"high": 0.5,
"medium": 0.5,
},
"attributes": {
"candidate_loans": [
{
"product_id": "INVMKT00000011",
"company_id": "CO00000011",
"risk_category": "medium",
"coupon": "6.0000",
"weight": "0.01315789",
"yield": "3.7000"
},
...
{
"product_id": "INVMHY00000090",
"company_id": "CO00000069",
"risk_category": "high",
"coupon": "7.7500",
"weight": "0.02173913",
"yield": "7.2000"
}
],
"calculated_yield": 7.85,
"bond_count": 61
},
"description": "The portfolio has a 50% target weighting to investments on the main market (Senior secured and Senior Unsecured bonds) and a 50% weighting to investments on the high yield market (subordinated bonds and Perpetuals. As well as a potentially higher return there is greater risk in this portfolio versus the Balanced portfolio."
},
{
"reference": "RWRP00000004",
"label": "Adventurous2",
"projected_return": "7.83",
"weightings": {
"high": 0.5,
"medium": 0.5,
},
"attributes": {
"candidate_loans": [
{
"product_id": "INVMKT00000011",
"company_id": "CO00000011",
"risk_category": "medium",
"coupon": "6.0000",
"weight": "0.01351351",
"yield": "3.7000"
},
...
{
"product_id": "INVMHY00000090",
"company_id": "CO00000069",
"risk_category": "high",
"coupon": "7.7500",
"weight": "0.02173913",
"yield": "7.2000"
}
],
"calculated_yield": 7.84,
"bond_count": 60
},
"description": "The portfolio has a 50% target weighting to investments on the main market (Senior secured and Senior Unsecured bonds) and a 50% weighting to investments on the high yield market. As well as a potentially higher return there is greater risk in this portfolio versus the Balanced portfolio."
}
]
}
Check a robowise configuration
URL: /robowise/{currency}/risk-profile-attributes/
Available Methods:
- POST: Submit a sample robowise configuration for analyses
Parameters:
Field | Description | Type |
---|---|---|
risk_profile_id | The ID of the risk profile to be considered. | Reference ID |
excluded_industries | An array of industry keys to exclude from the robowise profile. | String Array |
excluded_companies | An array of companies to exclude from the robowise profile. | Reference ID Array |
The fields returned are:
Field | Description | Type |
---|---|---|
candidate_bonds | The bonds that will be considered for inclusion. | Robowise Bond Summary object Array |
bond_count | The number of bonds to be considered | Decimal |
weighted_ytm | The weighted average yield to maturity of the resulting portfolio, assuming Robowise achieves an ideal spread of investments. | Integer |
issues | A list of issues that must be fixed before this profile can be used. | String Array |
Possible values in the issues field include:
- not-enough-bonds: There are not enough investments remaining in your custom portfolio to effectively diversify your funds. To rectify, you should exclude fewer companies and industries.
List Robowise Portfolios
URL: GET /customers/{}/investment-accounts/{}/robowise/
To retrieve a list of all robowise portfolios for a given investment account.
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/robowise/', headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/robowise/" \
-H "Authorization: Token $API_KEY" | jq .
Returned is a list of Robowise account objects
Available Expansions
Name | Description |
---|---|
performance |
Return the portfolio performance |
balance |
Return the portfolio cash balance |
ideals |
Return a breakdown of Robowise's current investment strategy |
Get Robowise Portfolio
URL: GET /customers/{}/investment-accounts/{}/robowise/{}/
Return details of a single robowise portfolio
As per the List call but returning a single Robowise account object rather than a list.
Available Expansions
Name | Description |
---|---|
performance |
Return the portfolio performance |
balance |
Return the portfolio cash balance |
ideals |
Return a breakdown of Robowise's current investment strategy |
Create Robowise Portfolio
URL: POST /customers/{}/investment-accounts/{}/robowise/
data = {
"parameters": {
"risk_profile_id": "RWRP00000002",
'reinvest_payments': False,
"profile_modifiers": {
"excluded_companies": ["CO00000001"],
"excluded_industries": ["space_mining"],
}
}
}
api = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/robowise/',
data=data, headers=headers)
curl -s -X POST "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/robowise/"
-H "Authorization: Token $API_KEY"
-H "Content-Type: application/json"
-d '{"parameters": {"risk_profile_id": "RWRP00000002", "profile_modifiers": {}}}' | jq .
On success, this endpoint returns the new Robowise account object
To create a robowise profile post a Robowise account object to this endpoint. Only the risk_profile_id
member is needed in the parameters
object, the fully serialized risk_profile
is ignored.
If no name is provided one will be selected from a default set of names managed by WiseAlpha.
Update Robowise Portfolio
URL: PUT /customers/{}/investment-accounts/{}/robowise/{}/
data = {
"parameters": {
"risk_profile_id": "RWRP00000002",
'reinvest_payments': False,
"profile_modifiers": {
"excluded_companies": ["CO00000001"],
"excluded_industries": ["space_mining"],
}
}
}
api = requests.put('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/robowise/$ROBOWISE_ACCOUNT_ID/',
data=data, headers=headers)
curl -s -X POST "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/robowise/$ROBOWISE_ACCOUNT_ID/"
-H "Authorization: Token $API_KEY"
-H "Content-Type: application/json"
-d '{"parameters": {"risk_profile_id": "RWRP00000002", "profile_modifiers": {}}}' | jq .
On success, this endpoint returns the updated Robowise account object
To update update and PUT a Robowise account object. Only the risk_profile_id
member is needed in the parameters
object, the fully serialized risk_profile
is ignored.
Fund a Robowise Portfolio
URL: POST /customers/{}/investment-accounts/{}/robowise/{}/fund/
data = {
"amount": "1000.00"
}
api = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/robowise/$ROBOWISE_ACCOUNT_ID/fund/',
data=data, headers=headers)
curl -s -X POST "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/robowise/$ROBOWISE_ACCOUNT_ID/fund/"
-H "Authorization: Token $API_KEY"
-H "Content-Type: application/json"
-d '{"amount": 1000.00}' | jq .
Funds can be transferred from the parent account, or directly deposited by using the account fund on the parent with the route_to
set to the child account id.
Field | Description | Type |
---|---|---|
amount | The amount to transfer from the parent account to the robowise account. | Decimal |
No currency is provided as each robowise account operates only in a single currency.
On success an Account Balance object is returned with the available cash balance for the account. As robowise is designed to invest any available cash, this is typically the amound just funded.
Withdraw cash from a Robowise Portfolio
There are two ways to withdraw cash from a robowise portfolio. You can directly set the current withdrawal behaviour to withdraw some or all of the value, or you can issue robowise withdrawal requests. These will executed in sequence and will set the withdrawal behaviour as needed.
Managing the withdrawal behaviour manually
URL: POST /customers/{}/investment-accounts/{}/robowise/{}/withdraw/
data = {
"type": "some",
"amount": "1000.00",
}
api = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/robowise/$ROBOWISE_ACCOUNT_ID/withdraw/',
data=data, headers=headers)
curl -s -X POST "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/robowise/$ROBOWISE_ACCOUNT_ID/withdraw/"
-H "Authorization: Token $API_KEY"
-H "Content-Type: application/json"
-d '{"amount": 1000.00, "type": "some"}' | jq .
For each robowise portfolio a target cash amount to withdraw can be set, or the portfolio can be marked to be cashed out completely. When a target amount is set, robowise will sell off enough of it's managed portfolio in order to reach the target. Funds will be move from the robowise account to the parent account as they become available.
The endpoint accepts a Robowise Withdrawal Behaviour object.
The current withdrawal behaviour can be checked via checking the Robowise account object and inspecting the withdrawal_behaviour
field. There can be only one withdrawal behaviour set at a time, if a second call is made it will supercede the current behaviour. If a target is set to withdraw 1000
, funds will be moved as they become available and the amount
returned in the withdrawal_behaviour
field will update to reflect this.
Issuing a Robowise Withdrawal Request
A request to withdraw cash from a robowise portfolio can be issued, this is similar to managing the withdrawal behaviour manually, but with a few important differences. You can issue several requests which will be executed in the order in which they are received. Only one request will be active at a given time and will remain active until the cash target for the withdrawal is achieved. An event will be generated when a given withdrawal request completes.
As an extra convenience you can instruct a withdrawal request to create a regular withdrawal request once it has completed. A robowise withdrawal request will move money from the robowise account to the holding account, and a regular withdrawal request will then move money from the holding account to the customer's registered bank account.
URL: POST /customers/{}/investment-accounts/{}/robowise/{}/withdrawals/
data = {
"amount": "100.00",
}
api = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/robowise/$ROBOWISE_ACCOUNT_ID/withdrawals/',
data=data, headers=headers)
Field | Description | Type |
---|---|---|
amount | The amount to transfer from the parent account to the robowise account. | Decimal |
on_complete | Optional field, it provides a mechanism for chaining a cash withdrawal from the top level account to the users registered bank account. | Object - see below |
The below is the only currently supported on_complete action
Field | Description | Type |
---|---|---|
action | Currently only withdraw_funds . |
String-Enum |
customer_reference | Only valid when the action is withdraw_funds . |
String |
Listing Robowise Withdrawal Requests
URL: GET /customers/{}/investment-accounts/{}/robowise/{}/withdrawals/
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/robowise/$ROBOWISE_ACCOUNT_ID/withdrawals/',
headers=headers)
A paged list of Robowise Withdrawal Request objects will be returned.
Updating a Robowise Withdrawal Request
URL: PATCH /customers/{}/investment-accounts/{}/robowise/{}/withdrawals/{}/
Once a withdrawal request has been issued it can be cancelled if it's not already completed. Only the state field can be updated and only to the cancelled state.
Transferring a Fractional Bond into a Robowise Portfolio
Fractional bond investments can be transferred from the parent account into robowise child accounts. This allows a customer to diversify their current holdings without incurring sales fees.
See Account Product Transfer for details on how to issue the transfer.
Robowise Portfolio Rebalances
List rebalances: URL: GET /customers/{}/investment-accounts/{}/robowise/{}/rebalances/
Get rebalance: URL: GET /customers/{}/investment-accounts/{}/robowise/{}/rebalances/{}/
Issue a rebalance: URL: POST /customers/{}/investment-accounts/{}/robowise/{}/rebalances/
# Create a manual rebalance
data = {}
api = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/robowise/$ROBOWISE_ACCOUNT_ID/rebalances/',
data=data, headers=headers)
If the portfolio is set to use a risk profile with a rebalance set to schedule
or manual
then a log all rebalances can be retrieved through these URLs. Continously rebalanced portfolios do not have rebalance logs.
See the Robowise Rebalance data type.
Close a Robowise Portfolio
URL: POST /customers/{}/investment-accounts/{}/robowise/{}/close/
data = {
"type": "transfer_to_parent",
}
api = requests.post('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/robowise/$ROBOWISE_ACCOUNT_ID/close/',
data=data, headers=headers)
curl -s -X POST "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/robowise/$ROBOWISE_ACCOUNT_ID/close/"
-H "Authorization: Token $API_KEY"
-H "Content-Type: application/json"
-d '{"type": "transfer_to_parent"}' | jq .
In order to close a robowise portfolio you need to issue a closure request and specify what how you want WiseAlpha to handle any remaining holdings in the account.
The endpoint accepts a Robowise Closure Request object. On acceptance of the request the account will be put into the closing
state and the process to close the account started. The robowise.closed
event will be generated when the closure is complete.
Robowise Risk Profiles
Customised risk profiles can be configured to create automated portfolios for your investors. Free cash in a portfolio will be invested according to the rules set-up in it's assigned risk-profile. Robowise portfolios can have additional modifiers as explained in Robowise Profile Modifiers.
Risk profiles can be private to an account manager, or shared within an organization.
Capital Allocation and Rebalancing
Robowise has two core concepts - capital allocation and rebalancing. A robowise portfolio will have a set of candidate products that it can invest in based on the risk profile and portfolio profile modifiers. The candidate products will have a weighting assgined. The most straightforward example of this is when a risk profile is set-up with a fixed set of products with fixed weightings per product.
The weighting corresponds to the percentage porfolio value the robowise portfolio should attempt to hold. It's important to note that this is portfolio value rather than notional, with portfolio value being notional * price + accrued
.
Allocation Types
A risk profile can have the below values for allocation_type
.
Name | Description |
---|---|
strict | Do not overallocate. |
flexible_to_max_holding | If some products are not available then re-allocate the funds in other products up to the max_holding limit defined in the risk profile. |
Initial Fund Allocation
When cash is made available to a portfolio an ideal holding will be created based on the current set and weighting of candidate products.
In strict allocation mode a buy will be created for each product matching that ideal value. If a product is not tradeable (e.g. it has repaid) then the cash will be held uninvested. It's also possible to hold cash in a porfolio by assigned weightings that sum up to less than 1.
In flexible allocation mode the portfolio will try and spend all the cash available. If a product is unavailable, whether due to a lack of liquidity in the market or because it's not tradeable, then the cash that would have been invested in that product is allocated to the other products in the portfolio. The total invested in a single product is still governed by the percentage set in the max_holding
limit defined in the portfolio.
Rebalancing
A risk profile can have the below values for rebalance_method
Name | Description |
---|---|
continuous | The portfolio will be continously rebalanced. |
manual | Rebalancing is only triggered manually. |
schedule | Reblancing runs on a schedule. |
Product Sets
A risk profile can have the below values for product_set
. This parameter controls how the list of candidate products for a porfolio is generated.
Name | Description |
---|---|
wisealpha_risk_category | Use a weighted porfolio based on WiseAlpha's risk categories. If this is set the weightings must be provided. |
fixed | Use a fixed product set. |
Weighting Methods
A risk profile can have the below values for weighting_method
. This parameter controls how a portfolio calculates the ideal holding of the various available candidate products in a given portfolio.
Name | Description |
---|---|
wisealpha_risk_category | Use the weightings parameter to define the percentage of each of WiseAlpha's risk categories to hold. |
flat | The weighting is calculated as 1/(number of candidate products). |
set_per_product | The weighting is defined per product by the portfolio manager. |
Risk Profile APIs
e
An example of creating a new risk profile and the data returned
# Create a new risk profile
data = {
"label": "Example Policy",
"currency": "GBP",
"allocation_type": "strict",
"weighting_method": "set_per_product",
"product_set": "fixed",
"fixed_products": [{
"product_reference": "INVMKT00000196",
"weighting": "0.5"
}],
"perpetuals_enabled": true
}
api = requests.post('$API_ROOT_URL/robowise/risk-profiles/', data=data, headers=headers)
{
"reference": "RWRP00000009",
"label": "Example Policy",
"projected_return": "3.06",
"weightings": {},
"attributes": {
"candidate_loans": [
{
"product_id": "INVMKT00000196",
"company_id": "CO00000138",
"risk_category": "medium",
"coupon": "3.7400",
"weight": "0.50000000",
"liquidity": "4088.9800",
"yield": "6.1160"
}
],
"calculated_yield": 3.06,
"bond_count": 1
},
"description": null,
"account_manager": null,
"weighting_method": "set_per_product",
"product_set": "fixed",
"fixed_product_ids": [
"INVMKT00000196"
],
"created_by": {
"email": "andrew@wisealpha.com",
"first_name": "Andrew",
"last_name": "Barrett",
"staff_id": "10006249"
},
"created_on": "2024-03-11T03:11:26.069507Z",
"updated_by": {
"email": "andrew@wisealpha.com",
"first_name": "Andrew",
"last_name": "Barrett",
"staff_id": "10006249"
},
"updated_on": "2024-03-11T03:11:26.069520Z",
"currency": "GBP",
"perpetuals_enabled": true,
"fixed_products": [
{
"product_reference": "INVMKT00000196",
"weighting": "0.5000"
}
],
"rebalance_method": "continuous",
"allocation_type": "strict"
}
List Risk Profiles: URL: GET /robowise/risk-profiles/
Create Risk Profile: URL: POST /robowise/risk-profiles/
Retrieve Risk Profile: URL: GET /robowise/risk-profiles/{}/
Update Risk Profile: URL: PUT/POST /robowise/risk-profiles/{}/
Delete Risk Profile: URL: DELETE /robowise/risk-profiles/{}/
Robowise Risk Profile Data Type
Name | Description | Data Type |
---|---|---|
reference | Risk profile reference. | Reference ID |
account_manager | This will be null if it's a shared profile, or owner if it is not. | User Info Type |
description | Optional description. | String |
label | The label displayed in the UX. | String |
projected_return | The current projected return for a ideally balanced portfolio using this profile. | Decimal |
rebalance_method | See Rebalancing. | String-Enum |
allocation_type | See Allocation Types. | String-Enum |
product_set | See Product Sets. | String-Enum |
fixed_product_ids | Deprecated - see fixed_products instead. |
Array of Product IDs |
fixed_products | See Fixed Product Data Type. | Array of Fixed Product Data Types |
weighting_method | See Weighting Methods. | String-Enum |
currency | The currency of the portfolio. | Currency |
perpetuals_enabled | True if the portfolio should hold perps - this setting will take precendence over products defined in a fixed product set. | Boolean |
Fixed Product Data Type
Name | Description | Data Type |
---|---|---|
product_reference | Product ID. | Product ID |
weighting | The ideal weighting of this product in a portfolio, based on portfolio value. | Decimal |
Rebalance Schedule APIs
An example of setting a schedule
# Create a new risk profile
data = {
"epoch": "2024-02-11T09:00:00Z",
"schedule_frequency": "monthly"
}
api = requests.put('$API_ROOT_URL/robowise/risk-profiles/$RISK_PROFILE_ID/schedule/', data=data, headers=headers)
{
"epoch": "2024-02-11T09:00:00Z",
"updated_on": "2024-03-11T03:19:51.430960Z",
"updated_by": {
"email": "andrew@wisealpha.com",
"first_name": "Andrew",
"last_name": "Barrett",
"staff_id": "10006249"
},
"schedule_frequency": "monthly",
"should_run_next_at": "2024-03-11T09:00:00Z",
"weekdays": null
}
Retrieve Rebalance Schedule: URL: GET /robowise/risk-profiles/{}/schedule/
Set Rebalance Schedule: URL: PUT /robowise/risk-profiles/{}/schedule/
Schedules are set relative to an epoch. E.g. setting up a weekly schedule with an epoch of 2024-02-11T09:00:00Z
and weekdays of ['mon', 'wed']
will create a portfolio rebalance weekly at 9am UTC every Monday and Wednesday following the epoch date.
Monthly schedules are set to repeat monthly relative to the date set in the epoch. If the epoch date is set after the 28th and the following month ends before the date set it will occur on the final day of the month.
If no schedule is set a 404 will be returned.
Rebalance Schedule Data Type
Name | Description | Data Type |
---|---|---|
epoch | The start date and time for the schedule. | Datetime |
updated | The date and time of the last schedule update. | Datetime |
updated_by | The user who last updated the schedule. | User Details |
should_run_next_at | The next time the schedule should fire. | Datetime |
schedule_frequency | One of monthly or weekly . |
String-Enum |
weekdays | Only valid for weekly , an array of weekdays, e.g. ['mon', 'wed'] . |
Array of weekday String-Enums |
Manual trigger API
# Rebalance all associated active profiles
data = {}
api = requests.post('$API_ROOT_URL/robowise/risk-profiles/$RISK_PROFILE_ID/rebalance/',
data=data, headers=headers)
Trigger a rebalance for all portfolios: URL: POST /robowise/risk-profiles/{}/rebalance/
This API is used to trigger a manual rebalance of all active portfolios under a risk profile. To rebalance a single portfolio see the Robowise Portfolio Rebalances API documentation.
Rebalance Log
List Rebalances: URL: GET /robowise/risk-profiles/{}/rebalances/
Get Rebalance: URL: GET /robowise/risk-profiles/{}/rebalances/{}/
Rebalance Log Data Type
Name | Description | Data Type |
---|---|---|
created_by_schedule | The schedule reference if the rebalance was created via a schedule. | Reference |
created_by_user | If manually created the user who triggered the rebalance. | User Details |
Rebalance Results Data Type
Name | Description | Data Type |
---|---|---|
executed | The number of robowise portfolios who have been rebalanced as a result of this rebalance. | Integer |
schedule | The number of robowise portfolios who are still scheduled to be rebalanced as a result of this rebalance. | Integer |
Available Expansions
Name | Description |
---|---|
results |
Returns the rebalance results |
Supported Ordering Fields
Field Name |
---|
created_on |
Reporting
Report Execution
Reports by default are generated asynchronously and are available to download for a period of 24 hours after generation. A webhook event will be fired when the report is available for download and the report-runs
endpoint can be polled to check for report completion.
Some reports can be asked to be generated synchronously, in this case the report content will be returned as part of the call and not stored for download later.
Reporting Data Types
Report Run object
Name | Description | Data Type |
---|---|---|
reference | A unique reference for the report run. | Reference |
created | The time the report run was created | String-Enum |
status | One of pending , completed or failed |
String-Enum |
report_type | See Report Types below | String-Enum |
report_generation | One of synchronous or asynchronous |
String-Enum |
report_format | See Report Formats below | String-Enum |
report_args | The arguments for the report, for the supported arguments on a given report type, see the section for the specific report below | Dictionary |
content | Only included in a response to a synchrous report run creation request, will contain the report data. | Object |
Report Types
The following reports are offered over the API
Name | Tag | Description |
---|---|---|
Account Statement | account_statement |
A report showing a detailed account statement. |
Bond Investment Detail | bond_investment_detail |
A report that will show all investment transactions for a given bond. Available as csv , json and pdf . |
Portfolio Value Report | portfolio_report |
A report that will show the porfolio value. Available as csv , json and pdf . |
Returns Report | returns_report |
A report showing the Portfolio Value, Gain/Loss, Interest Earned and other measures for all of your current and closed investments since the account was opened. Available as csv |
Income Statement | income_statement |
A report that provides income and capital gains information to assist with tax reporting. Replaces the Tax Report. Available as pdf . |
Tax Report (deprectated) | tax_report |
A report to help tax reporting. Available as pdf . |
Account Statement Report
{
"report_type": "account_statement",
"report_format": "csv",
"report_generation": "asynchronous",
"report_args": {
"investment_account_reference": "INVACC00001786",
"from_date": "2020-01-01",
"until_date": "2022-01-01",
"currency": "GBP"
}
}
Available as csv
and pdf
.
The report arguments are
Name | Description | Data Type |
---|---|---|
investment_account_reference | The investment account to generate the report for. (required) | Reference |
currency | The currency to generate the report for. (required) | Reference |
from_date | The date from which to generated data for (inclusive of date). (optional) | Reference |
until_date | The date until which to generate data for (exclusive of date). (optional) | Reference |
Bond Investment Detail Report
{
"report_type": "bond_investment_detail",
"report_format": "json",
"report_generation": "synchronous",
"report_args": {
"investment_account_reference": "INVACC00001786",
"from_date": "2020-01-01",
"until_date": "2022-01-01",
"product": "INVMKT00000160"
}
}
{
"report_type": "bond_investment_detail",
"report_format": "csv",
"report_generation": "asynchronous",
"report_args": {
"investment_account_reference": "INVACC00001786",
"from_date": "2020-01-01",
"until_date": "2022-01-01",
"product": "INVMKT00000160"
}
}
This report supports synchronous generation for json
. Available as json
, csv
and pdf
.
The report arguments are
Name | Description | Data Type |
---|---|---|
investment_account_reference | The investment account to generate the report for. (required) | Reference |
product | The product reference to generate the report for. (required) | Reference |
from_date | The date from which to generated data for (inclusive of date). (optional) | Reference |
until_date | The date until which to generate data for (exclusive of date). (optional) | Reference |
Portfolio Value Report
{
"report_type": "portfolio_report",
"report_format": "csv",
"report_args": {
"investment_account_reference": "INVACC00001786",
"currency": "GBP",
"pricing_date": "2022-01-01"
}
}
The report arguments are
Name | Description | Data Type |
---|---|---|
investment_account_reference | The investment account to generate the report for. (required) | Reference |
currency | The currency to generate the report for. (required) | Currency |
pricing_date | The date to generate the report for. (optional) | Currency |
Available as csv
.
Returns Report
{
"report_type": "returns_report",
"report_format": "csv",
"report_args": {
"investment_account_reference": "INVACC00001786",
"currency": "GBP"
}
}
The report arguments are
Name | Description | Data Type |
---|---|---|
investment_account_reference | The investment account to generate the report for. (required) | Reference |
currency | The currency to generate the report for. (required) | Currency |
Available as csv
.
Income Statement
{
"report_type": "income_statement",
"report_format": "pdf",
"report_args": {
"investment_account_reference": "INVACC001786",
"currency": "GBP",
"from_date": "2020-01-01",
"until_date": "2022-01-01",
}
}
Available as pdf
.
The report arguments are
Name | Description | Data Type |
---|---|---|
investment_account_reference | The investment account to generate the report for. (required) | Reference |
currency | The currency to generate the report for. (required) | Reference |
from_date | The date from which to generate data for (inclusive of date). (optional) | Reference |
until_date | The date until which to generate data for (exclusive of date). (optional) | Reference |
Tax Report (deprecated)
{
"report_type": "tax_report",
"report_format": "pdf",
"report_generation": "asynchronous",
"report_args": {
"investment_account_reference": "INVACC00001786",
"from_date": "2020-01-01",
"until_date": "2022-01-01",
"currency": "GBP"
}
}
Available as pdf
.
The report arguments are
Name | Description | Data Type |
---|---|---|
investment_account_reference | The investment account to generate the report for. (required) | Reference |
currency | The currency to generate the report for. (required) | Reference |
from_date | The date from which to generate data for (inclusive of date). (optional) | Reference |
until_date | The date until which to generate data for (exclusive of date). (optional) | Reference |
Report Formats
Depending on the report, a combination of the available formats is available for download.
Name | Format | Description |
---|---|---|
CSV | csv |
Comma seperated values text/csv |
pdf |
Portable Document Format (PDF) application/pdf |
|
JSON | json |
Javascript Object Notation (JSON) application/json |
XLSX | xlsx |
Excel spreadsheet application/xlsx |
Report Runs
List Report Runs: URL: GET /reporting/report-runs/
Get a Report Run: URL: GET /reporting/report-runs/{}/
Create a Report Run: URL: POST /reporting/report-runs/
Report generation is scheduled by creating a report run object. Some report_type
and report_format
combinations support synchronous generation of the report content where the report will be returned as part of the call to create. Asynchronous reports will be generated after the report run is created and an event will be fired when the report is finished, or the report status can be polled waiting for the report_status
to turn to completed
. Once a report is in the completed
state it will be available to download for 24 hours.
See the Report Type documentation for details on the report arguments required to generate each report type.
Supported Ordering
Name | Description |
---|---|
created |
Sort from oldest to newest. |
-created |
Sort from newest to oldest. |
Supported Filtering
Name | Description |
---|---|
report_generation |
Filter by asynchronous or asynchronous . |
Downloading report runs
URL: GET /reporting/report-runs/{}/download/
If the report run status is set to completed
it will be available to be downloaded for a period of 24 hours from the download URL.
Trading on WiseAlpha
WiseAlpha supports different execution models depending on the underlaying market being traded on. Peer to peer orders are created via the /market/
endpoint and request for quotes (RFQs) from market makers can be created on the /rfq/
endpoint. The /markets/
endpoint will list all made markets that can be traded on by the caller.
RFQ Flow
In a RFQ based market, investors (or someone working on their behalf) will issue RFQs to get quotes for purchasing products. Any market makers operating in the market can respond with a quote. The issuer of the RFQ can then confirm any of the return quotes. On confirmation of a quote an order is created. Orders are then executed by the market process. Settlement depends on the market, with near instant settlement supported.
Market makers can run in auto quote or manual quote mode, or a mixture of both.
Manual Quote Flow
If operating with manual quotes, a market maker will be notified when there is a new RFQ available to be quoted on. The market maker can then respond to the RFQ with a Quote if they want to.
Auto Quote Flow
If operating with automatic quotes, the system will generate a quote from the market maker in response to an RFQ based on the pricing the market maker has loaded into the system. This can be controlled with further settings including how to respond with limited inventory etc.
Peer to Peer Flow
In the peer to peer market, investor buys and sells are matched and executed. Orders are split as needed during the matching process. Trading happens at a fixed market price, with the prices marked daily.
Markets
WiseAlpha supports multiple markets where investors issue RFQs and Market Makers respond to them.
Overview
Managed markets in WiseAlpha consist of one or more Market Makers responding to Request for Quotes (RFQs) from investors looking to invest in a given product.
Market Makers can be set-up to auto-respond to a RFQs with a given bid/offer price or can respond with a price via the API in response to a new RFQ being posted. Each new RFQ will trigger an event that can be received via a webhook if set-up, or new RFQs can be polled for.
Markets
URL: GET /markets/
URL: GET /markets/{market-reference}/
Name | Description | Data Type |
---|---|---|
reference | Market reference | Reference |
state | One of open , suspended |
String-Enum |
timezone | Market timezone | String |
name | Market name | String |
description | Market description | String |
A market in WiseAlpha is an exchange where listed products can be bought and sold. Each market in WiseAlpha can be configured with open hours and market holidays. A market may also be suspended during trading hours if needed. Fractionalised products bought on one market must be sold back to the same market.
Market settings
URL: GET /markets/{market-reference}/settings/
URL: GET /markets/{market-reference}/settings/{setting-name}/
URL: PUT /markets/{market-reference}/settings/{setting-name}/
The following settings are retrievable and updatable depending on permissions. Market settings give a way of controlling various attributes of a market, e.g. min/max order sizes and min holdings.
Name | Description | Value Data Type |
---|---|---|
opening_hours | The market opening days and hours | Array of opening hours objects |
minimum_order_sizes | The minimum order sizes by currency | Currency value dictionary |
maximum_order_sizes | The maximum order sizes by currency | Currency value dictionary |
minimum_holdings | The minimum holding by currency | Currency value dictionary |
default_rfq_ttl | The default RFQ time to live in seconds | Integer |
fixed_fx_rates | Any fixed FX rates for the market | Array of fixed FX rates |
Opening Hours Data Type
Name | Description | Data Type |
---|---|---|
day | Day of the week, one of mon , tue , wed , thu , fri , sat or sun . |
String-Enum |
opens | The time the market opens. | Time |
closes | The time the market closes. | Time |
Fixed FX Rate Data Type
Name | Description | Data Type |
---|---|---|
currency_from | Currency to convert from. | Currency |
currency_to | Currency to convert to. | Currency |
rate | The fixed fx rate. | Decimal |
Restricted market settings
URL: GET /markets/{market-reference}/restricted-settings/
URL: GET /markets/{market-reference}/restricted-settings/{setting-name}/
URL: PUT /markets/{market-reference}/restricted-settings/{setting-name}/
The following settings are retrievable and updatable depending on permissions. The bid/ask fee are built on-top of the price a market maker charges and are payable to the market entity.
Name | Description | Value Data Type |
---|---|---|
bid_fee | The market bid fee | Decimal |
ask_fee | The market ask fee | Decimal |
Market state change requests
URL: GET /markets/{market-reference}/state-change-requests/
URL: GET /markets/{market-reference}/state-change-requests/{reference}/
URL: POST /markets/{market-reference}/state-change-requests/
{
"reference": "MKTST00000001",
"created": "2023-01-16T22:30:15.764267Z",
"created_by": {
"email": "andrew@wisealpha.com",
"first_name": "Andrew",
"last_name": "Barrett",
"is_active": true,
"staff_id": "10000003",
"date_joined": "2022-11-15T02:56:03.279799Z",
"role": "superuser"
},
"previous_state": "open",
"requested_state": "suspended"
}
The state of the market can be updated by creating a new market state change request. Previous requests can be read through the API.
To create a new state change request, post the requested state.
Name | Description | Data Type |
---|---|---|
requested_state | As per the market state values. | String-Enum |
Supported Ordering Fields
Field Name |
---|
created |
-created |
Holidays
URL: GET /calendar/CAL00000005/holidays/
URL: POST /calendar/CAL00000005/holidays/
URL: PATCH/PUT/DELETE /calendar/CAL00000005/holidays/{}/
Manage market holidays through the above URLs. A market holiday object is as follows:
Field | Description | Type |
---|---|---|
date | The date of the holiday. | Date |
calendar_name | The name of the calendar the holiday belongs to. | String |
description | The description of the holiday. | String |
Supported Filtering
Field Name | Support Lookups |
---|---|
date |
All date lookups supported |
Supported Ordering Fields
Field Name |
---|
created |
-created |
date |
-date |
Request for Quotes (Investor)
RFQ Endpoints
To return a list of all RFQs generated for a given investment account:
api = requests.get('$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/rfqs/', headers=headers)
curl -s "$API_ROOT_URL/customers/$CUSTOMER_ID/investment-accounts/$INVESTMENT_ACCOUNT_ID/rfqs/" \
-H "Authorization: Token $API_KEY" | jq .
List RFQs URL: GET /customers/{}/investment-accounts/{}/rfqs/
Retrieve RFQ URL: GET /customers/{}/investment-accounts/{}/rfqs/{}/
Create an RFQ URL: POST /customers/{}/investment-accounts/{}/rfqs/
This method returns a list of all the RFQs generated for a given investment account.
Available Filters
Name | Description |
---|---|
status |
One of expired or open |
expires |
See Datetime field lookups |
created |
See Datetime field lookups |
Supported Ordering Fields
Field Name |
---|
created |
expires |
RFQ Object
Field | Description | Type |
---|---|---|
reference | The RFQ reference | Reference |
created | When the RFQ was created | Datetime |
expires | When the RFQ expires | Datetime |
notional_amount | The notional amount to quote on | Decimal |
notional_currency | The currency of the product | Currency |
product_id | The product to trade | Reference |
market_reference | The market to trade in | Reference |
investment_account_reference | The investment account issuing the RFQ | Reference |
quote_type | Either buy to indicate the RFQ is to buy a product or sell to indicate the RFQ is to sell a product. |
String-Enum |
allow_partial_fulfilment | Set to true to allow the request to be partially filled, false if the whole quote is to be filled in a single trade. In the case of partial fulfilment the market must also support partial fulfilment. |
Boolean |
warnings | Only present when issuing a transient RFQ, will return an array of any problems with the RFQ data | Array of Strings |
Available Expansions
Name | Description |
---|---|
quotes |
If called by an investor or account manager it will return all the Quotes available for the RFQ. If called by a market maker it will return only the Quotes issued by the caller |
customer_details |
Will return information about the investor issuing the RFQ |
related_account_balance |
Only valid when called by an investor's account manager, it will return the account balance of the investor issuing the RFQ |
bond |
Will return information about the product the RFQ references. |
inventory |
Only valid when called by a market maker, it will return the current notional held by the market maker for the product the RFQ calls for |
Quote Object
Field | Description | Type |
---|---|---|
reference | The Quote reference | Reference |
rfq_reference | The RFQ reference | Reference |
market_maker_reference | The market maker reference | Reference |
created | When the Quote was created | Datetime |
expires | When the Quote expires | Datetime |
notional | The notional amount of the quote | Decimal |
price | The price of the quote | Decimal |
currency | The currency of quote | Currency |
cost_of_notional | The cost of the notional | Decimal |
cost_of_accrued | The cost of the accrued | Decimal |
total_cost | The total cost of the quote | Decimal |
Available Expansions
Name | Description |
---|---|
confirmation |
A (Quote Confirmation)[#quote-confirmation-objec] object or null if the quote has not been confirmed |
market_maker_name |
The name of the market maker associated with the quote |
Quote Confirmation Object
Field | Description | Type |
---|---|---|
reference | The Quote Confirmation reference | Reference |
confirmed_on | The time of confirmation | Reference |
order_reference | Either a sell order or buy order reference between on the quote type | Reference |
Create a RFQ
URL: POST /customers/{}/investment-accounts/{}/rfqs/
To create an RFQ, the below fields must be provided.
Field | Description | Type |
---|---|---|
notional_amount | The notional amount | Decimal |
notional_currency | The product currency | Currency |
quote_type | Either buy to indicate the RFQ is to buy a product or sell to indicate the RFQ is to sell a product. |
String-Enum |
product_reference | The Product Reference to quote for | Reference |
market_reference | The market to trade on, if this is left blank the investment account's default market will be used | Reference |
allow_partial_fulfilment | Set to true to allow the request to be partially filled, false if the whole quote is to be filled in a single trade. In the case of partial fulfilment the market must also support partial fulfilment. |
Boolean |
transient | If true it will return any warnings associated with the creation of the RFQ as well as transient quote if there are market makers with auto-quoting turned on |
Boolean |
The RFQ will be returned. If there are any market makers set to auto-quote on the product then the quotes field will be expanded and the auto quotes returned.
List RFQ Quotes
URL: GET /customers/{}/investment-accounts/{}/rfqs/{}/quotes/
Returns a page list of Quotes.
Available Filters
Name | Description |
---|---|
status |
One of expired or open |
expires |
See Datetime field lookups |
created |
See Datetime field lookups |
Supported Ordering Fields
Field Name |
---|
created |
expires |
Confirm Quote
Confirm a Quote URL: POST /customers/{}/investment-accounts/{}/rfqs/{}/quotes/{}/confirm/
To confirm a quote send a POST request to the quote's confirm endpoint. When a quote is confirmed either a buy or sell order will be created against the investor's investment account. After a quote is confirmed and the order created it will be executed by the market process and settled according to the market set-up.
Market Making
URL: GET /market-making/
To get a list of all market making accounts the caller has permission to act for
This API will return a list of all the market making accounts the caller has permission for. Each market making account is associated with the market the market making is trading in, and the investment account that holds the fractional bonds within WiseAlpha.
api = requests.get('$API_ROOT_URL/market-making/', headers=headers)
curl -s "$API_ROOT_URL/market-making/" \
-H "Authorization: Token $API_KEY" | jq .
Or to read details of a specific market maker account:
api = requests.get('$API_ROOT_URL/market-making/MKTM00000001/', headers=headers)
curl -s "$API_ROOT_URL/market-maker/MKTM00000001/" \
-H "Authorization: Token $API_KEY" | jq .
The list request returns a list of market making accounts as the following JSON:
{
"count":1,
"next":null,
"previous":null,
"results":[
{
"reference":"MKTM00000001",
"market_reference":"MKT00000001",
"investment_account_reference":"INVACC00000001",
"name":"Market Maker One",
"quote_expiry_in_seconds": 300,
}
]
}
The following settings can be configured on a market maker
Name | Description | Data Type |
---|---|---|
quote_expiry_in_seconds | The default quote expiry | Integer |
default_execution_type | One of auto , manual or not_trading |
String-Enum |
low_inventory_notification_threshold | A threshold to notify about if the market maker's holding drops below | Decimal |
rfq_notification_preference | One of mute , notify_all or notify_if_price_set |
String-Enum |
require_fat_finger_check_in_csv_upload | Indicates whether to subject CSV price uploads to a fat finger check | Boolean |
fat_finger_threshold | The threshold to trigger the fat finger check on | Decimal |
Market Maker Pricing
To get a list of all current prices (historical prices will not be returned)
api = requests.get('$API_ROOT_URL/market-making/$MARKET_MAKER_REFERENCE/products/', headers=headers)
Data return in the form
{
"count":1,
"next":null,
"previous":null,
"results":[
{
"created": "2000-01-01T00:00:00Z",
"product_id": "INVMKT00000001",
"bid": "98.50",
"ask": "100.50",
"max_exposure": null,
"execution_type": "auto"
}
]
}
To get a specific product price
api = requests.get('$API_ROOT_URL/market-making/$MARKET_MAKER_REFERENCE/products/$PRODUCT_ID/', headers=headers)
List Prices: URL: GET /market-making/{}/products/
Retrieve a Product Price: URL: GET /market-making/{}/products/{}/
Set a price (via POST): URL: POST /market-making/{}/products/
Set a price (via PATCH): URL: PATCH /market-making/{}/products/{}/
Market makers can set prices on any product listed on the market.
To set a new price you can POST to the list endpoint, or directly PATCH the product URL. In not provided the max_exposure will be set to null and the execution type will be the default exection type as configured on the market maker. It is possible to set only the bid or ask price and leave the other null.
Setting prices via CSV or XLSX
Retrieve CSV template: URL: GET /market-making/{}/products/get-csv-template/
Set prices via CSV: URL: POST /market-making/{}/products/set-prices/
Prices can be set via CSV upload to the above endpoint as per the table below.
Name | Description | Data Type |
---|---|---|
price_data | The CSV or XLSX price file | File |
unlisted_behavior | One of unchanged or remove |
String-Enum |
confirmations | List of updates that have failed the fat-finger check but have been confirmed as acceptable anyway. | Array of pricing review items |
The unlisted_behaviour
field controls what to do if a product is not present in the price list. If set to unchanged
it will retain it's current pricing. If set to remove
then any current pricing will be removed.
The confirmations
array is used in the case where a fat finger check is configured on the market maker. The fat finger check is an optional threshold set where if the price changes by more than the threshold the API will indicate that confirmation is required to set the price.
On success, if some prices has been updated, the endpoint returns a 201 response code. If prices haven't been updated due to the fat-finger check and confirmations have not been provided, then the api will return a 200 response code, and the client should review the list of pricing review items to determine which of the updates need confirmation.
On success or a request for confirmation response, the response is an array of pricing response items, one per line of input data in the provided file. Pricing response items are structured as follows:
Name | Description | Data Type |
---|---|---|
row | The row that this response refers to. | Integer (zero based - file header is row 0) |
review_data | List of items that have been/will be changed. | Review data object |
warnings | Issues found in the provided data. | Array of warning items |
If the input line has an error that renders it unuseable, such as a missing/unknown ISIN or unparseable input field, then the review_data is null.
The review data object contains the following fields:
Name | Description | Data Type |
---|---|---|
product_id | The product ID. | Product ID |
company_name | Company name | String |
company_logo | A url pointing to a company logo | String |
isin_code | International Securities Identification Number | String |
currency | Product currency | Currency |
maturity | Product maturity | Date |
yield_to_maturity | YTM | Decimal |
coupon_string | Coupon | Decimal |
previous_bid | The bid befor update | Decimal |
new_bid | The bid after update | Decimal |
previous_ask | The ask before update | Decimal |
new_ask | The ask after update | Decimal |
previous_risk_category | The risk category before the update | String |
new_risk_category | The risk category after the update | String |
previous_complexity | The complexity before the update | String |
new_complexity | The complexity after the update | String |
requires_confirmation | Indicates whether the price update requires confirmation via the confirmations array. | Boolean |
has_confirmed | Indicaters whether the price update has been confirmed. | Boolean |
Warning items contain the following fields:
Name | Description | Data Type |
---|---|---|
error_type | The nature of the error | String |
message | A brief description of the nature of the error | String |
Warnings include
- Missing investment ISIN
- Unknown/unrecognised investment
- Unknown rating, complexity or risk category
- Unparseable ask or bid
- Bid greater than ask
In the event of a more serious error, the endpoint returns a 400 BAD REQUEST
return code and a list of items indicating the nature of the error. Serious errors include
- Unparseable input data
- No data in the file
- Missing ISIN, bid or ask columns
Market Maker Product Data Type
Name | Description | Data Type |
---|---|---|
created | The time the price was last updated. | Datetime |
product_id | The relevant product ID. | Reference ID |
bid | The bid price. | Decimal |
ask | The ask price. | Decimal |
max_exposure | Only used in the case of auto execution_type, will limit the notional held. | Decimal |
execution_type | One of manual , auto or not-trading . |
String-Enum |
RFQs
To retrieve a list of all open RFQs available to be quoted
api = requests.get('$API_ROOT_URL/market-making/$MARKET_MAKER_REFERENCE/rfqs/', headers=headers)
Data return in the form
{
"count":1,
"next":null,
"previous":null,
"results":[
{
"reference": "RFQ00000001",
"created": "2022-07-25T09:30:00Z",
"expires": "2022-07-25T09:33:00Z",
"notional_amount": "10000.00",
"notional_currency": "GBP",
"product_id": "INVMKT00000001",
"market_reference": "MKT00000001",
"investment_account_reference": "INVACC00000001",
"quote_type": "buy",
"warnings": null,
"allow_partial_fulfilment": false,
}
]
}
List RFQs: URL: GET /market-making/{}/rfqs/
Retrieve RFQ: URL: GET /market-making/{}/rfqs/{}/
Available Filters
Name | Description |
---|---|
status |
One of expired or open |
expires |
See Datetime field lookups |
created |
See Datetime field lookups |
Supported Ordering Fields
Field Name |
---|
created |
expires |
Quoting a RFQ
URL: POST /market-making/{}/rfqs/{}/quote/
Name | Description | Data Type |
---|---|---|
notional_amount | The notional amount to quote for | Decimal |
price | The price offered | Decimal |
quote_expiry_in_seconds | The TTL (time to live) for the quote in seconds | Integer |
Quotes
List Quotes: URL: GET /market-making/{}/quotes/
Retrieve Quote: URL: GET /market-making/{}/quotes/{}/
A market maker can retrieve the Quotes they have created.
Available Filters
Name | Description |
---|---|
status |
One of expired or open |
expires |
See Datetime field lookups |
created |
See Datetime field lookups |
Supported Ordering Fields
Field Name |
---|
created |
expires |
Peer to Peer Market
On the WiseAlpha peer to peer market users directly trade with each other.
Market Data Types
We use the following data types in the market endpoints:
Buy Request object
Name | Description | Data Type |
---|---|---|
product_id | The product ID to create a buy order for. | Reference ID |
type | One of either principal or gross . If the buy is of type principal then the order will be create to acquire the specific amount of principal regardless of current price or accrued interest on the product. A buy of type gross will create an order of the specified amount and will buy the appropriate amount of principal to achieve that. |
String-Enum |
amount | Either the amount of principal to acquire or the amount of money to invest depending on the type . |
Decimal |
currency | Currency to invest with, currently this must match the currency that the product is listed in. | Currency |
price | The price to buy the product at. For an explanation of product prices see the pricing under general section. | Decimal |
Buy Quote object
This object has the same fields as the Buy Request object with the additional fields below added.
Name | Description | Data Type |
---|---|---|
principal | The amount of principal that will be purchased. | Decimal |
interest | The amount of accrued interest that will be purchased. | Decimal |
total | The total amount the user needs to spend to complete this purchase. | Decimal |
warnings | Any reasons that this request might fail, e.g., price does not match bond, or the customer is attempting to buy more than is |
Sell Request object
Name | Description | Data Type |
---|---|---|
product_id | The product ID to create a sell order for. | Reference ID |
amount | The amount of principal to sell. | Decimal |
currency | Currency to invest with, currently this must match the currency that the product is listed in. | Currency |
price | The price to sell the product at. For an explanation of product prices see pricing under the general section. | Decimal |
Sell Quote object
This object has the same fields as the Sell Request object with the additional fields below added.
Name | Description | Data Type |
---|---|---|
principal | The amount of principal that will be sold. | Decimal |
interest | The amount of accrued interest that will be sold. | Decimal |
service_fee | The service fee that will be taken (As per the T&C, this is the service fee the customer has accumulated while holding this asset.) | Decimal |
sale_fee | The sale fee that will be taken (As per the T&C, selling an investment early is subject to a small fee.) | Decimal |
total | This is the total, including interest and all fees, the user will receive when selling the asset. | Decimal |
warnings | Any reasons that this request might fail, e.g., price does not match bond, or the customer is attempting to sell more than they own. | Array of Strings |
/market/
import json
import requests
headers = {
'Authorization': 'Token $API_KEY',
'Content-Type': 'application/json',
}
market_request = {
"customer_id": "10000001",
"investment_account_id": "INVACC00000001",
"buys": [{
"product_id": "INVMKT00000001",
"type": "principal",
"amount": "500.00",
"currency": "GBP",
"price": "100"
}, {
"product_id": "INVMKT00000002",
"type": "gross",
"amount": "500.00",
"currency": "GBP",
"price": "100"
}],
"sells": [{
"product_id": "INVMKT00000003",
"amount": "500.00",
"currency": "GBP",
"price": "100"
}]
}
api = requests.post('$API_ROOT_URL/market/', headers=headers, data=json.dumps(market_request))
read -r -d '' DATA << EOM
{
"customer_id": "10000001",
"investment_account_id": "INVACC00000001",
"buys": [
{
"product_id": "INVMKT00000001",
"type": "principal",
"amount": "500.00",
"currency": "GBP",
"price": "100"
},
{
"product_id": "INVMKT00000002",
"type": "gross",
"amount": "500.00",
"currency": "GBP",
"price": "100"
}
],
"sells": [
{
"product_id": "INVMKT00000003",
"amount": "500.00",
"currency": "GBP",
"price": "100"
}
]
}
EOM
curl -s -X POST $API_ROOT_URL/market/ \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
The above command returns JSON structured like this:
{
"balances": [{
"currency": "GBP",
"amount": "1681.94"
}],
"buys_orders": [{
"id":"MKTBUY00000001",
"original_id":"MKTBUY00000001",
"product_id":"INVMKT00000001",
"type":"principal",
"state":"open",
"currency":"GBP",
"amount":"520.00",
"principal":"500.00",
"price":"100.0000",
"created":"2017-12-20T12:35:31.403366Z"
},{
"id":"MKTBUY00000002",
"original_id":"MKTBUY00000002",
"product_id":"INVMKT00000002",
"type":"gross",
"state":"open",
"currency":"GBP",
"amount":"500.00",
"principal":null,
"price":"100.0000",
"created":"2017-12-20T12:35:31.390342Z"
}
],
"sell_orders": [{
"id":"MKTSELL00000001",
"original_id":"MKTSELL00000001",
"product_id":"INVMKT00000003",
"state":"open",
"currency":"GBP",
"amount":"500.00",
"price":"100.0000",
"created":"2017-12-20T13:50:19.839640Z"
}]
}
Use the market endpoint to create buy and sell orders on the WiseAlpha secondary market. A successful market
request will return the new account balance after the orders have been placed along with details of
the orders created. Details of unfulfilled orders can also be retrieved via the
buy_orders and sell_orders entrypoints.
On success, all of the buys and sells have been placed on the market, though
they will not have been fulfilled. In particular, sell orders (and buy orders with no liquidity)
will likely remain unfulfilled until another customer creates a matching order. For this reason, we
recommend that you only allow the customer to generate buy orders when the bond sell_liquidity
is non-zero. Sell orders may take a few days to complete.
The customer will be notified of success or failure of the order via buy-order
and sell-order
events
as documented in the events section.
If the market request fails, none of the buys and sells will have been placed on the market, The request cannot partially succeed.
Available Methods:
- POST: Creates buy and sell orders on the WiseAlpha marketplace
POST request:
The market request takes the following arguments.
Name | Description | Data Type |
---|---|---|
customer_id | User account making the trade, if not present the account is assumed to be the account associated with the API key in use. | Customer ID |
investment_account_id | Investment account to make the trade on. | Reference ID |
buys | An array of buy requests. | Array of Buy Requests |
sells | An array of sell requests. | Array of Sell Requests |
It returns a JSON object containing the following fields:
Name | Description | Data Type |
---|---|---|
balances | The funds remaining uninvested in the customer's account. See balances for details. | Array of balance objects |
buy_orders | A list of buy orders created by the request. See buy_orders for details. | Array of Buy orders |
sell_orders | A list of sell orders created by the request. See sell_orders for details. | Array of Sell orders |
/market/quote/
import json
import requests
headers = {
'Authorization': 'Token $API_KEY',
'Content-Type': 'application/json',
}
market_request = {
"customer_id": "1000001",
"investment_account_id": "INVACC00000001",
"buys": [{
"product_id": "INVMKT00000001",
"type": "principal",
"amount": "500.00",
"currency": "GBP",
"price": "100"
}, {
"product_id": "INVMKT00000002",
"type": "gross",
"amount": "500.00",
"currency": "GBP",
"price": "100"
}],
"sells": [{
"product_id": "INVMKT00000003",
"amount": "500.00",
"currency": "GBP",
"price": "100"
}]
}
api = requests.post('$API_ROOT_URL/market/quote/', headers=headers, data=json.dumps(market_request))
read -r -d '' DATA << EOM
{
"customer_id": "10000001",
"investment_account_id": "INVACC00000001",
"buys": [
{
"product_id": "INVMKT00000001",
"type": "principal",
"amount": "500.00",
"currency": "GBP",
"price": "100"
},
{
"product_id": "INVMKT00000002",
"type": "gross",
"amount": "500.00",
"currency": "GBP",
"price": "100"
}
],
"sells": [
{
"product_id": "INVMKT00000003",
"principal": "500.00",
"principal_currency": "GBP",
"price": "100"
}
]
}
EOM
curl -s -X POST $API_ROOT_URL/market/quote/ \
-H "Authorization: Token $API_KEY" \
-H "Content-Type: application/json" \
-d "$DATA" | jq .
The above command returns JSON structured like this:
{
"customer_id": "10000001",
"investment_account_id": "INVACC00000001",
"buys": [{
"product_id": "INVMKT00000001",
"type": "principal",
"amount": "500.00",
"currency": "GBP",
"price": "100",
"principal": "500.00",
"interest": "1.50",
"total": "501.50",
"warnings": []
}, {
"product_id": "INVMKT00000002",
"type": "gross",
"amount": "500.00",
"currency": "GBP",
"price": "100",
"principal": "499.00",
"interest": "1.00",
"total": "500.00",
"warnings": []
}],
"sells": [{
"product_id": "INVMKT00000003",
"amount": "500.00",
"currency": "GBP",
"price": "100",
"principal": "500.00",
"interest": "2.50",
"service_fee": ".25",
"sale_fee": "1.25",
"total": "501.00",
"warnings": []
}]
}
Use the /market/quote/
endpoint to get a preview of what will happen during a market buy
or sale.
When buying an investment, this endpoint returns the amount of principal
and interest
that
will be purchased, and the total
amount that the user will need to invest to fulfill the order.
These amounts are related via the following formula:
total = principal * price + interest
For "type": "gross"
orders, the amount
corresponds to the total amount the customer wants
to spend on the investment. In this case, amount == total
and the amount of principal the customer
will receive is given by principal
.
For "type": "principal"
orders, the amount
corresponds to the amount of principal the
customer wants to purchase. In this case, amount == principal
and the total
gives the amount
the user will have to pay for the investment.
When selling an investment, the amount
always specifies the amount of principal the customer
intends to sell. In this case, the endpoint returns the amount of accrued interest they will
receive, and the fees taken during the sale. The total
field gives total cash that will be
returned to the user.
As when you're buying from the marketplace you're also buying accrued interest. and the market price can fluctuate these calculations can vary.
The results of a successful call to /market/quote/
may be posted to /market/
directly, although a successful call to /market/quote/
is no guarantee of the trade
going through successfully as the /market/
endpoint runs additional validation that the
/market/quote/
endpoint does not.
Available Methods:
- POST: Returns a quote for the WiseAlpha marketplace
Request body arguments for POST
As per /market/
Name | Description | Data Type |
---|---|---|
buys | Quotes for the buy requests passed in. | Array of Buy quotes |
sells | Quotes for the sell requests passed in. | Array of Sell quotes |
Events and Webhooks
As part of your API integration you can configure webhooks to receive callbacks when certain events happen in WiseAlpha. The endpoint receiving these webhooks must return a success response to the WiseAlpha server. WiseAlpha will attempt to deliver an event to a webhook URL 5 times, with an increasing delay between attempts until a success response is returned. After 5 delivery attempts the event will no longer be delivered.
Alternatively, you can always fetch the event via the /events/
endpoint below.
Events
Every event contains the following fields:
Field | Description | Type |
---|---|---|
id | The unique event identifier | Reference ID |
created | The timestamp for when the event was created | DateTime |
event_type | The type of the event | String - one of the Event Type values listed below |
customer_id | The customer the event applies to | Customer ID |
data | Additional information specific to the event | A dictionary containing additional information specific to the event |
The WiseAlpha platform produces the following events.
Event Type | Description |
---|---|
account.aml-check-passed | The AML check is complete and passed. The user can now invest. |
account.aml-check-failed | The AML check is complete and failed. The user will need to upload ID documents before they can invest. |
account.identity-documents-verified | The WiseAlpha team have verified and approved the user's identity documents. |
account.document-rejected | The WiseAlpha team have rejected a document that you uploaded. You will need to upload the document in question again. |
account.additional-document-required | We require that you upload an additional document to further verify your account. (E.g., a bank statement to verify account ownership.) |
account.bank-details-rejected | The user's bank details are invalid. The user will need to upload new bank details before transfer can be processed. |
account.bank-transfer-credited | The user's bank transfer has been completed and the amount credited to his WiseAlpha account. |
account.investor-type-approved | The user's investor type has been approved. |
buy-order.price-change | The prices of the assets in the user's buy order has changed before it could be completed. The buy order will need to be reconfirmed. |
buy-order.filled | The buy order has been filled. |
buy-order.cancelled | The buy order has been cancelled. This usually occurs because none of the requisite asset is available to fill the order. |
investment.payment | An investment has made a payment. |
investment.repayment | An investment has been repaid. |
investment.partial_repayment | An investment has been partially repaid. |
market-making.quote-confirmed | A quote has been executed. |
market-making.quote-executed | A quote has been confirmed. |
market-making.rfq-created | An RFQ has been created and is available to be quoted. |
report-run.completed | A report run has been completed and is available to be downloaded. |
robowise.closed | A robowise account has been closed. |
robowise.withdrawal-complete | A withdrawal of funds from a robowise sub-account to it's parent account has completed. |
sell-order.price-change | The prices of the assets in the user's sell order has changed before it could be completed. The sell order will need to be reconfirmed. |
sell-order.filled | The sell order has been filled. |
sell-order.cancelled | The sell order has been cancelled. This is a very rare eventuality - usually, sell orders remain until the asset is sold. |
The account events
These events are generated when the WiseAlpha platform changes the state of a user's account, e.g. when the WiseAlpha platform completes an AML check.
The event contains the following additional information in the data field:
Field | Description | Type |
---|---|---|
user_profile | User's profile object after the update | Profile object |
Details of the next steps required - if any - are contained in the validation object in the user data.
The aml-check-passed and aml-check-failed events
These events are generated when the WiseAlpha platform completes the AML check for a user.
If the AML check returns "pass" we generate the aml-check-passed
event. The user
can start investing up to the AML investment threshold - currently £5,000 - without restriction.
If the AML check returns "fail" we generate the aml-check-failed
event. In this case,
the user will not be able to transfer funds or invest until they have uploaded identity
documents.
The identity-documents-verified event
This event is generated when the WiseAlpha team has reviewed and verified the ID documents
provided by the user and the AML process is now complete. The user is in the invest
state and can invest and withdraw funds as he sees fit.
The document-rejected event
This event is generated when the WiseAlpha team has reviewed a document, but found it to be not acceptable. The event contains the following additional fields.
Field | Description | Type |
---|---|---|
document.type | The ID of the document that was rejected. See Onboarding for details of valid document types. | String |
document.type_display | A human-readable string describing the document type. | String |
document.original_file_name | The name provided when the document was uploaded. | String |
document.rejection_reason | The reason the wisealpha team rejected this document. | String |
The user's verification object will also be updated to indicate which documents need updating.
The additional-document-required event
From time to time, we may require additional documentation. E.g., we may require that you upload a bank statement if we are unable to automatically verify that the user owns/controls the linked bank account.
Field | Description | Type |
---|---|---|
document.type | The ID of the document that was rejected. See Onboarding for details of valid document types. | String |
document.type_display | A human-readable string describing the document type. | String |
The user's verification object will also be updated to indicate that an additional document is now required.
The bank-details-rejected event
Before we can transfer money to an external bank account, we check the user's configured bank-details.
If the bank details are deemed to be invalid, e.g., if the sort code does not identify
a real bank, then we issue an account.bank-details-rejected
event. In this case the
user should upload new bank details.
Field | Description | Type |
---|---|---|
rejection_reason | The reason the Wisealpha team rejected the bank details. | String |
Note that if the bank details are valid, but can't be confirmed as belonging to the user,
then we will send an appropriate account.additional-document-required
event instead.
The bank-transfer-credited event
This event is generated when the fund transfer process is complete, i.e. when funds have
arrived in our system and been credited to your account. In addition to the user_profile
object, the event contains the following additional items:
Field | Description | Type |
---|---|---|
wisealpha_reference | WiseAlpha's reference for this transfer. | String |
amount_allocated | The amount allocated to your account for this transfer | Decimal |
currency | The currency of the amount allocated in this transfer | Currency |
The wisealpha_reference
matches the reference returned by the initial fund request.
You can use this to correlate this event with the fund request that initiated the process.
The amount_allocated
gives the amount credited to your account.
The buy-order and sell-order events
Buys and sells of marketplace investments are completed offline. The WiseAlpha platform sends events to notify the user when the order for each investment completes.
All buy-order and sell-order events include the following fields:
Field | Description | Type |
---|---|---|
order_id | The order ID | Reference ID |
original_id | The ID of the order originally submitted | Reference ID |
investment | Details of the investment being bought or sold | Investment Object |
currency | The currency of this order | Currency |
trade_type | (Buys only) The type of this trade: gross , principal or auto_reinvest_trade |
String |
WiseAlpha fulfils orders by matching buys with sells in the marketplace. This means that any given order can be filled over a number of transactions.
The investment object contains the following fields:
Field | Description | Type |
---|---|---|
product_id | Product id | Reference ID |
company_name | The name of the company | String |
The -order.filled events
We raise this event when the order has been completely filled, or partially filled then the remainder cancelled.
Field | Description | Type |
---|---|---|
amount_requested | The amount originally requested | Decimal |
amount_filled | The amount we were able to fulfil | Decimal |
For buy orders, even principal
orders, the above amounts are the total amount requested/spent, including accrued interest.
For sell orders, the above amounts refer to the amount of principal.
For sell orders, we also include the following fields:
Field | Description | Type |
---|---|---|
cash_received | The amount of cash returned to the user, including accrued interest and fees taken. | Decimal |
The -order.cancelled events
We raise this event when the order is cancelled. The event contains the following additional fields:
Field | Description | Type |
---|---|---|
reason | The reason the order was cancelled | String |
amount_remaining | The amount remaining unfulfilled in this order | Decimal |
currency | The currency of the order | Currency |
If the order has been partially filled before being cancelled, you'll also get an -order.filled event telling you this.
The -order.price_change events
We raise this event when the asset underlying the order changes in price. It indicates that the order has been
suspended. The user will need to confirm that they want to continue with this order via the /orders/confirm
entrypoint. Alternatively, they can cancel the order. For buy orders, this returns the order funds to the
user's wallet.
Field | Description | Type |
---|---|---|
old_price | The old price of the asset | Decimal |
new_price | The new price of the asset | Decimal |
amount_remaining | The amount remaining unfulfilled in this order | Decimal |
currency | The currency of the order | Currency |
The investment events
These events are generated when an investment makes a payment.
All the events include the following fields:
Field | Description | Type |
---|---|---|
investment | Details of the investment being paid out. | Investment object |
currency | The currency of the payout | Currency |
interest_payment | The interest paid out | Decimal |
reinvesting_proceeds | Whether we are going to reinvest the proceeds | Boolean |
For marketplace investments, the investment
field contains details of the bond, e.g., the
wise ticker and company name.
The reinvesting_proceeds
flag is set to true
if you have selected to reinvest the proceeds of this
investment, and if there is some of this investment available on the marketplace. In this case
the proceeds of the investment are used to purchase more of the investment. Otherwise, the proceeds
are added to the user's uninvested funds. They'll need to either withdraw the funds or manually reinvest
them as they see fit.
(For repayment
and partial_repayment
events, reinvesting_proceeds
is currently always False.
At some future time, WiseAlpha plan to offer an automated reinvestment tool. When the user selects
to use such a tool, this flag will be true
and the proceeds will automatically be used to purchase
other investments.)
We issue the investment.payment
event when an investment makes an interest payment. The proceeds
are your share of the interest accrued on this investment since it last made a payment, or since
it was issued if this is the first payment.
We issue the investment.repayment
event when an investment repays, either because it has matured or
because the company issuing the bond has decided to repay early. The proceeds include both the
interest accrued since the last payment and repayment of the capital. Repayment events contain the
following additional fields:
Field | Description | Type |
---|---|---|
call_price | The price at which the bond issuer is buying back the principal | Decimal |
principal_payment | The principal paid out | Decimal |
The call_price
is the price at which the principal is being repaid. A call price of 100
means the
principal is being bought back at parity. In some cases, particularly if the bond is being paid back
early, the call price may be greater than 100, in which case the user is making a capital
gain on the investment. The principal_payment
field gives the amount of capital being paid back to
the user. It's value equals the principal invested multiplied by the call price.
The investment.partial_repayment
event is raised when the investment in question partially pays
back early.
The robowise.closed and robowise.withdrawal-complete events
Field | Description | Type |
---|---|---|
account-reference | The account reference of the robowise account the event pertains to. | String |
Delivering events via the Webhook API
Use webhooks to be notified about events that happen to a WiseAlpha account.
To configure your webhook settings, you'll need to contact Contact Support and provide them with an endpoint or endpoints that webhook events should be sent to. We'll then provide you with a private key that should be used to validate that a given webhook delivery was made by WiseAlpha.
For more information on this have a look at "Validate the Signature" section.
/events/: Fetching events directly
api = requests.get('$API_ROOT_URL/events/',
headers=headers)
curl -s "$API_ROOT_URL/events/" \
-H "Authorization: Token $API_KEY" | jq .
Returns pagination object containing a list of events.
{
"count": 6,
"next": null,
"previous": null,
"results": [
{
"id": "EVENT00000099",
"created": "2017-11-29T17:48:59.786838Z",
"event_type": "account.aml-check-passed",
"data": {
"user_profile": { ... }
}
}
}
...
]
}
Available Methods:
- GET: Returns detailed information about an account.
You can also fetch events directly by making a GET web request to the /events/
endpoint
as shown.
Supported Ordering Fields
Field Name |
---|
created |
Supported Filtering
Field Name | Support Lookups |
---|---|
created |
All datetime lookups supported |
Validate the signature of an event
When you register your endpoint you will be provided a private key, $WEBHOOK_KEY
, that you can use to validate
that a given webhook delivery was made by WiseAlpha. The signature will be present in the x-wisealpha-signature
header.
To calculate the expected signature, generated an HMAC SHA-256 digest on the request body using your private key and check it against the expected header.
import json
import binascii
import hashlib
import hmac
import base64
from sanic import Sanic
from sanic.response import json
app = Sanic()
@app.route("/")
async def home(request):
return json({"hello": "world"})
@app.route("/webhooks", methods=['POST', 'GET'])
async def webhooks(request):
try:
signature = request.headers.get('x-wisealpha-signature', '')
key_bytes = base64.b64decode('$WEBHOOK_KEY')
calculated = base64.b64encode(hmac.new(key_bytes, request.body, digestmod=hashlib.sha256).digest()).decode(encoding='ascii')
if signature == calculated:
# Process request
pass
except Exception as ex:
# Log exception, but swallow it and return 200 so the endpoint does not get disabled
pass
return json({"valid": signature == calculated})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=9999)
# No shell example - see the python example
WiseAlpha Services
Services information can be viewed via the /services/
endpoint. A superuser can enable or disable services via a PATCH request.
Displaying WiseAlpha services
URL: GET /services/
Returns a list of all service objects.
URL: GET /services/{service_id}/
Returns a service object identified by its service_id (e.g. GET /services/market/
).
Service object
Name | Description | Data Type |
---|---|---|
id | Integer | |
service_id | String | |
enabled | Boolean | |
last_cycle | String | |
description | String | |
time_to_alarm | Integer | |
sleep_time | Integer |
Enabling/disabling services
URL: PATCH /services/{service_id}/
You must have superuser access to perform this action.
A service can be enabled or disabled via a PATCH request (e.g. PATCH /services/market/
) with a JSON object (e.g. {"enabled": "true"}
.
It is not currently possible to edit other service object fields via the API.