Investment Platform API
This guide shows you how to use the API to create an investment for an investor. The API allows you to collect information about the investment process in order to document the compliant brokerage of financial products.
We'll assume that you have created an investor as part of following the guide for creating an investor and have stored an investor ID that we will use in this guide.
In the course of this guide, we will create a simple script that shows the basic interactions with the API. At the end of this guide, you will also find the complete script for you to copy, paste and try out. Remember to insert your account specific information before running the script.
First we are going to import the packages that we need and set up some basic variables. The client ID and client secret will be provided to you. The campaign ID is set up for you as well during the product creation.
import binascii
import os
import requests
URL = 'https://demo.cashlink.de/api/external'
CLIENT_ID = '<your client ID>'
CLIENT_SECRET = '<your client secret>'
CAMPAIGN_ID = '<campaign id>'
INVESTOR_ID = '<investor id from previous guide>'
Now we write a helper function that follows the OAuth protocol to retrieve an access token that we will use to authenticate the API calls.
def authenticate():
r = requests.post(f'{URL}/oauth/token', data={
'grant_type': 'client_credentials',
'scope': 'investors:write investors:read investments:write investments:read documents:write',
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET
})
assert r.status_code == 200, r.content
return r.json()['access_token']
We add an additional helper function that with every call creates a random idempotency key. In your application, you would use an idempotency key that correlates to the internal object on your side.
def make_key():
return binascii.hexlify(os.urandom(8)).decode()
With the investor ID at hand, we create an invitation for this investor. We're also importing the investors answers to the latest knowledge and experience questionnaire as well as answers to the self-disclosure questions.
# Create a basic invitation with campaign, investor and units
r = requests.post(
f'{URL}/v2/invitations/',
json={
"investor_id": INVESTOR_ID,
"campaign_id": CAMPAIGN_ID,
"units": 1100
},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
invitation_id = r.json()['id']
As the investor walks through the investment process in your frontend, update the invitation with the data. When all data has been set, you can use the invitation to create an investment.
# Patch the invitation with the required self-disclosure answers
r = requests.patch(
f'{URL}/v2/invitations/{invitation_id}/',
json = {
'self_disclosure_submitted_at': '2021-11-15T08:33:45.617Z',
"self_disclosure_monthly_income": True,
"self_disclosure_net_worth_100k": True
},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
# Patch the invitation with the survey answers
r = requests.patch(
f'{URL}/v2/invitations/{invitation_id}/',
json = {
'survey_submitted_at': '2022-03-22T07:14:13.630308+00:00',
'survey': [],
},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
# Patch the invitation with the required survey waiver
r = requests.patch(
f'{URL}/v2/invitations/{invitation_id}/',
json = {
'survey_waiver': 'NO_ANSWERS',
},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
# Use the invitation to create an investment
r = requests.post(
f'{URL}/v2/investments/',
json={
'invitation_id': invitation_id,
"signed_at": "2022-03-22T08:33:45.617Z"
},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
investment_id = r.json()['id']
For the investment to finish, we need to associate the wallet of the investor with the investment.
# get wallet for investor
r = requests.get(
f'{URL}/v2/investors/{INVESTOR_ID}/wallets/',
headers={**headers}
)
assert r.status_code < 300, r.content
# investor must at least have a single wallet
investor_wallets = r.json()
assert len(investor_wallets) > 0
wallet_id = investor_wallets[0]['id']
# patch investment to set wallet
r = requests.patch(
f'{URL}/v2/investments/{investment_id}/',
json={
'wallet': wallet_id
},
headers={**headers}
)
assert r.status_code < 300, r.content
We can now use the investments endpoint to retrieve all information about the investment.
r = requests.get(
f'{URL}/v2/investments/{investment_id}/',
headers={**headers}
)
assert r.status_code < 300, r.content
status = r.json()['status']
print(investment_id)
print(status)
This is how the full script will look like.
import binascii
import os
import requests
URL = 'https://demo.cashlink.de/api/external'
CLIENT_ID = '<your client ID>'
CLIENT_SECRET = '<your client secret>'
CAMPAIGN_ID = '<campaign id>'
INVESTOR_ID = '<investor id from previous guide>'
def authenticate():
r = requests.post(f'{URL}/oauth/token', data={
'grant_type': 'client_credentials',
'scope': 'investors:write investors:read investments:write investments:read documents:write',
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET
})
assert r.status_code == 200, r.content
return r.json()['access_token']
def make_key():
return binascii.hexlify(os.urandom(8)).decode()
if __name__ == '__main__':
headers = {
'Authorization': f'Bearer {authenticate()}',
}
# Create a basic invitation with campaign, investor and units
r = requests.post(
f'{URL}/v2/invitations/',
json={
"investor_id": INVESTOR_ID,
"campaign_id": CAMPAIGN_ID,
"units": 1100
},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
invitation_id = r.json()['id']
# Patch the invitation with the required self-disclosure answers
r = requests.patch(
f'{URL}/v2/invitations/{invitation_id}/',
json = {
'self_disclosure_submitted_at': '2021-11-15T08:33:45.617Z',
"self_disclosure_monthly_income": True,
"self_disclosure_net_worth_100k": True
},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
# Patch the invitation with the survey answers
r = requests.patch(
f'{URL}/v2/invitations/{invitation_id}/',
json = {
'survey_submitted_at': '2022-03-22T07:14:13.630308+00:00',
'survey': [],
},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
# Patch the invitation with the required survey waiver
r = requests.patch(
f'{URL}/v2/invitations/{invitation_id}/',
json = {
'survey_waiver': 'NO_ANSWERS',
},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
# Use the invitation to create an investment
r = requests.post(
f'{URL}/v2/investments/',
json={
'invitation_id': invitation_id,
"signed_at": "2022-03-22T08:33:45.617Z"
},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
investment_id = r.json()['id']
# get wallet for investor
r = requests.get(
f'{URL}/v2/investors/{INVESTOR_ID}/wallets/',
headers={**headers}
)
assert r.status_code < 300, r.content
# investor must at least have a single wallet
investor_wallets = r.json()
assert len(investor_wallets) > 0
wallet_id = investor_wallets[0]['id']
# patch investment to set wallet
r = requests.patch(
f'{URL}/v2/investments/{investment_id}/',
json={
'wallet': wallet_id
},
headers={**headers}
)
assert r.status_code < 300, r.content
r = requests.get(
f'{URL}/v2/investments/{investment_id}/',
headers={**headers}
)
assert r.status_code < 300, r.content
status = r.json()['status']
print(investment_id)
print(status)