Quickstart guide
This guide should give you a quick start for the integration of the Issuer API. We'll use easy to read python code. For HTTP interactions we will use the requests package.
At the end of this guide, you will also find the complete python script for you to copy, paste and try out.
Getting started
Before you get started make sure that you've installed an up-to-date python version. To run the script you will also need the requests package.
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 during the set up of the demo environment.
import binascii
import os
import requests
URL = 'https://demo.cashlink.de/api/external'
CLIENT_ID = '...'
CLIENT_SECRET = '...'
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': 'issuers:read issuers:write products:read products:write 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()
Creating an issuer
First we create an issuer by providing issuer company data.
if __name__ == '__main__':
headers = {
'Authorization': f'Bearer {authenticate()}',
}
# Upload document
r = requests.post(
f'{URL}/issuer/v2/documents/',
files={'file': ('identity_proof.pdf', b'ASD', 'application/pdf')},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
identity_proof_id = r.json()['id']
# Upload document
r = requests.post(
f'{URL}/issuer/v2/documents/',
files={'file': ('structure_proof.pdf', b'ASD', 'application/pdf')},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
structure_proof_id = r.json()['id']
# Create issuer
r = requests.post(
f'{URL}/issuer/v2/issuers/',
json={
'natural_person': {
'salutation': 'MR',
'forename': 'John',
'surname': 'Smith',
'birth_date': '1990-01-31',
'birth_place': 'Berlin',
'citizenship': 'DEU',
'street': 'Hauptstr. 37',
'city': 'Frankfurt',
'zip': '60316',
'country': 'DEU',
'phone': '+49 123 456 789',
'is_pep': False,
'is_subject_to_us_tax': False
},
'legal_person': {
'city': 'string',
'commercial_register': 'Amtsgericht München',
'commercial_register_number': 'HRB 12344',
'company_identity_proof_id': identity_proof_id,
'company_name': 'Test GmbH',
'company_structure_proof_id': structure_proof_id,
'country': 'DEU',
'phone': '0173 2093790',
'street': 'string',
'zip': 'string'
},
'bank_account': {
'account_holder': 'Big GmbH',
'bank': 'Commerzbank Frankfurt',
'bic': 'GENODEF1ERG',
'country': 'DEU',
'currency': 'EUR',
'iban': 'DE27700901000000063292',
'shared_account': False
}
},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
issuer_id = r.json()['id']
print(f'Issuer: {issuer_id}')
Creating a product
After we have created an issuer, we create a product by referencing the issuer.
# Upload document
r = requests.post(
f'{URL}/issuer/v2/documents/',
files={'file': ('issuance-terms.pdf', b'ASD', 'application/pdf')},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
issuance_document_id = r.json()['id']
# Create product
r = requests.post(
f'{URL}/issuer/v2/products/',
json={
'name': 'Test Bond',
'product_type': 'BOND',
'agio_percent': '0',
'provide_nominal_value': True,
'nominal_value': {
'amount': '1000',
'decimals': 3,
'currency': 'EUR'
},
'max_issuable_amount': 1000000,
'step_size': 1,
'payment_deadline': 3,
'cancellation_deadline': 14,
'network': 'polygon-amoy',
'code': 'TEST25',
'calculation_factor': 1,
'lock_in_time': '2026-09-22T11:58:26.318Z',
'issuance_document_id': issuance_document_id,
'issuer_id': issuer_id,
'ewpg': True,
'isin': 'US0378331005',
'publication_restricted': False
},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
product_id = r.json()['id']
print(f'Product: {product_id}')
Creating a listing
# Retrieve distribution platform data
r = requests.get(
f'{URL}/issuer/v2/distribution-platforms/',
headers={**headers}
)
assert r.status_code < 300, r.content
distribution_platform_id = r.json()['results'][0]['id']
r = requests.get(
f'{URL}/issuer/v2/distribution-platforms/{distribution_platform_id}/',
headers={**headers}
)
assert r.status_code < 300, r.content
# Check that is_allowed is set to True
assert r.json()['is_allowed'] == True
# Create listing on the distribution platform
r = requests.post(
f'{URL}/issuer/v2/listings/',
json={
'product_id': product_id,
'distribution_platform_id': distribution_platform_id
},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
print(f'Listing: {r.json()['id']}')
Full script
Below you find the full script for you to copy, paste and try out.
import binascii
import os
import requests
URL = 'https://demo.cashlink.de/api/external'
CLIENT_ID = '...'
CLIENT_SECRET = '...'
def authenticate():
r = requests.post(f'{URL}/oauth/token', data={
'grant_type': 'client_credentials',
'scope': 'issuers:read issuers:write products:read products:write 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()}',
}
# Upload document
r = requests.post(
f'{URL}/issuer/v2/documents/',
files={'file': ('identity_proof.pdf', b'ASD', 'application/pdf')},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
identity_proof_id = r.json()['id']
# Upload document
r = requests.post(
f'{URL}/issuer/v2/documents/',
files={'file': ('structure_proof.pdf', b'ASD', 'application/pdf')},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
structure_proof_id = r.json()['id']
# Create issuer
r = requests.post(
f'{URL}/issuer/v2/issuers/',
json={
'natural_person': {
'salutation': 'MR',
'forename': 'John',
'surname': 'Smith',
'birth_date': '1990-01-31',
'birth_place': 'Berlin',
'citizenship': 'DEU',
'street': 'Hauptstr. 37',
'city': 'Frankfurt',
'zip': '60316',
'country': 'DEU',
'phone': '+49 123 456 789',
'is_pep': False,
'is_subject_to_us_tax': False
},
'legal_person': {
'city': 'string',
'commercial_register': 'Amtsgericht München',
'commercial_register_number': 'HRB 12344',
'company_identity_proof_id': identity_proof_id,
'company_name': 'Test GmbH',
'company_structure_proof_id': structure_proof_id,
'country': 'DEU',
'phone': '0173 2093790',
'street': 'string',
'zip': 'string'
},
'bank_account': {
'account_holder': 'Big GmbH',
'bank': 'Commerzbank Frankfurt',
'bic': 'GENODEF1ERG',
'country': 'DEU',
'currency': 'EUR',
'iban': 'DE27700901000000063292',
'shared_account': False
}
},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
issuer_id = r.json()['id']
print(f'Issuer: {issuer_id}')
# Upload document
r = requests.post(
f'{URL}/issuer/v2/documents/',
files={'file': ('issuance-terms.pdf', b'ASD', 'application/pdf')},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
issuance_document_id = r.json()['id']
# Create product
r = requests.post(
f'{URL}/issuer/v2/products/',
json={
'name': 'Test Bond',
'product_type': 'BOND',
'agio_percent': '0',
'nominal_amount': {
'amount': '1000',
'decimals': 3,
'currency': 'EUR'
},
'max_issuable_amount': 1000000,
'step_size': 1,
'payment_deadline': 3,
'cancellation_deadline': 14,
'network': 'polygon-amoy',
'code': 'TEST25',
'calculation_factor': 1,
'lock_in_time': '2026-09-22T11:58:26.318Z',
'issuance_document_id': issuance_document_id,
'issuer_id': issuer_id,
'ewpg': True,
'isin': 'US0378331005',
'publication_restricted': False
},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
product_id = r.json()['id']
print(f'Product: {product_id}')
# Retrieve distribution platform data
r = requests.get(
f'{URL}/issuer/v2/distribution-platforms/',
headers={**headers}
)
assert r.status_code < 300, r.content
distribution_platform_id = r.json()['results'][0]['id']
r = requests.get(
f'{URL}/issuer/v2/distribution-platforms/{distribution_platform_id}/',
headers={**headers}
)
assert r.status_code < 300, r.content
# Check that is_allowed is set to True
assert r.json()['is_allowed'] == True
# Create listing on the distribution platform
r = requests.post(
f'{URL}/issuer/v2/listings/',
json={
'product_id': product_id,
'distribution_platform_id': distribution_platform_id
},
headers={**headers, 'X-Idempotency-Key': make_key()}
)
assert r.status_code < 300, r.content
print(f'Listing: {r.json()['id']}')
Last updated
Was this helpful?