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.

Make sure Python and the requests package are installed.

Remember to insert your account specific information before running the script.

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?