Create Account

This page will help you get familiar with the account endpoint.

The Brokerage API provides a way for you to manage brokerage accounts for your users.

Overview

This document will walk you through the following steps in order to create a user account:

  • Fetch Legal Documents
  • Create Account Record
  • Perform Video Identification
  • Set Experience Profile

This document will walk you through the process of creating a new user account on the lemon.markets brokerage platform. To ensure high compatibility with your development setup, we will discuss the API interface of lemon.markets while using the command line utilities curl and jq. If you use an auto-generated API client (e.g. from our OpenAPI description) or an HTTP client in a programming language, you should be able to adapt these examples to your needs.

Preparations: Fetch Current Set of Onboarding Documents

In order to prepare the process, download the current list of legal documents, so you can present them to the user.

NOTE: As this data is not classified as personal information, you are invited to cache the data within your backend infrastructure, as long as you can guarantee the data is not modified.

curl -sS -H 'LMG-Data-Privacy-Access-Principal: backend-nobody' \
        -H 'LMG-Data-Privacy-Access-Justification: open_account' \
        -H 'Authorization: Bearer <your-api-key>' \
        'https://sandbox.api.lemon.markets/v1/agreements' | jq 

Which should result in a response like this:

{
  "data": [
    {
      "id": "agr_9902271f791d413aad781763c61b9bb0",
      "type": "privacy_policy",
      "url": "https://agreements.sandbox.lemon.markets/test-document.pdf",
      "language": "de",
      "name": "Datenschutzerklärung"
    },
    {
      "id": "agr_8ec894e1ec764a339e172292dff9aeff",
      "type": "terms_and_conditions",
      "url": "https://agreements.sandbox.lemon.markets/test-document.pdf",
      "language": "de",
      "name": "Allgemeine Geschäftsbedingungen"
    }
  ],
  "pagination": {
    "next_cursor": null
  }
}

For more details, see our API reference:
Get Latest Agreements.

Collect User Information

Now that we have the legal documents, we need to present the user with the privacy policy and make sure they agree to
the privacy policy before you collect any personal data in the onboarding flow. Refer to your onboarding materials for
more details on how to achieve this.

Once you have collected all the data points required to onboard the user, you can move on to the next step:

Create User Account Reference

In order to have a reference for the user, we need to create an account.

curl --request POST \
     --url https://sandbox.api.lemon.markets/v1/accounts \
     --header 'accept: application/json' \
     --header 'authorization: Bearer lP9y2II79cpPC3ie7lrHCmYcMWMsoTId' \
     --header 'content-type: application/json' \
     --header 'LMG-Data-Privacy-Access-Principal: backend-erika.mustermann%40example.com' \
     --header 'LMG-Data-Privacy-Access-Justification: open_account' \
     --data '
{
  "accepted_agreements": [
    {
      "accepted_at": "2023-06-29T14:39:29Z",
      "agreement_id": "agr_9902271f791d413aad781763c61b9bb0"
    },
    {
      "accepted_at": "2023-06-29T14:39:29Z",
      "agreement_id": "agr_8ec894e1ec764a339e172292dff9aeff"
    }
  ],
  "customer": {
    "date_of_birth": "1964-08-12",
    "email": "[email protected]",
    "employment": {
      "annual_salary": "gte_50k_lt_75k_eur",
      "sector": "public_sector",
      "status": "employed"
    },
    "firstname": "Erika",
    "gender": "female",
    "lastname": "Mustermann",
    "marital_status": "married",
    "nationalities": [
      "DE"
    ],
    "phone_number": "+49172997318",
    "place_of_birth": {
      "city": "Berlin",
      "country": "DE"
    },
    "registered_address": {
      "city": "Köln",
      "country": "DE",
      "line_1": "Heidestraße 17",
      "postal_code": "51147"
    },
    "tax_residencies": [
      {
        "country": "DE",
        "tax_identification_number": "123/456/78901"
      }
    ]
  },
  "declaration_of_acting_on_own_account": true
}
'

This will return a similar response object. We will focus on the added property id. In subsequent steps, we'll use
that identifier to refer to the account as is being set up:

{
  "id": "cusa_c2c3f89ec0524b6e818ce00c16e4897f",
  "cash_account": null,
  "customer": {
    …
  },
  "declaration_of_acting_on_own_account": true,
  "history": [
    {
      "status": "created",
      "timestamp": "2023-06-29T14:43:03.937676+00:00"
    }
  ],
  "securities_account": null,
  "status": "created"
}

For more details, see our API reference: Create Account.

Inspect Onboarding Checks

With our account identifier we can now check which parts of the onboarding process are still pending:

curl --request GET \
     --url https://sandbox.api.lemon.markets/v1/accounts/cusa_c2c3f89ec0524b6e818ce00c16e4897f/checks \
     --header 'LMG-Data-Privacy-Access-Justification: onboarding.check_status' \
     --header 'LMG-Data-Privacy-Access-Principal: backend-cusa_c2c3f89ec0524b6e818ce00c16e4897f' \
     --header 'accept: application/json' \
     --header 'authorization: Bearer lP9y2II79cpPC3ie7lrHCmYcMWMsoTId'

This will provide us with a response like this:

{
  "data": [
    {
      "data": null,
      "history": [
        {
          "status": "processing",
          "timestamp": "2023-06-29T14:43:03.937676+00:00"
        }
      ],
      "status": "processing",
      "type": "risk_assessment"
    },
    {
      "data": null,
      "history": [
        {
          "status": "action_required",
          "timestamp": "2023-06-29T14:43:03.937676+00:00"
        }
      ],
      "status": "action_required",
      "type": "experience"
    },
    {
      "data": null,
      "history": [
        {
          "status": "action_required",
          "timestamp": "2023-06-29T14:43:03.937676+00:00"
        }
      ],
      "status": "action_required",
      "type": "identity_verification"
    }
  ],
  "pagination": {
    "next_cursor": null
  }
}

In the response list, we can see that there's an action required for both the experience and identity_verification
domains. You can complete both in any order, let's start with the identity verification.

For more details, see our API reference:
Get Onboarding Checks.

Start Video Identification

Before presenting the user with the identity verification flow, we need to fully understand how this flow works:

  1. We start by making a call to /accounts/:account_id/identity_verification. The response will contain a web URL.
  2. Display the contents of the URL to the user.
    • For a web-based onboarding flow, this most likely involves redirecting the user.
    • For a mobile onboarding flow, this probably involves an (in-app?) browser.
  3. Now the user will go through the identity verification process.
  4. Once the process is complete, the user needs to return to your onboarding flow. In order to do so, we will use a redirect URI as supplied in step (1.).
    • For a web-based onboarding flow, this is probably a URL within your own onboarding flow.
    • For a mobile onboarding flow, this probably involves opening an app-based URI scheme like my-app://brokerage/id/success.

With this general understanding of the identity verification process, we can create a request for a mobile app, that
will eventually redirect to my-app://brokerage/id/success or my-app://brokerage/id/failure to indicate whether or
not the identity verification process succeeded.

curl --request POST \
     --url https://sandbox.api.lemon.markets/v1/accounts/cusa_c2c3f89ec0524b6e818ce00c16e4897f/identity_verification \
     --header 'LMG-Data-Privacy-Access-Justification: onboarding.identity_verification' \
     --header 'LMG-Data-Privacy-Access-Principal: backend-cusa_c2c3f89ec0524b6e818ce00c16e4897f' \
     --header 'accept: application/json' \
     --header 'authorization: Bearer lP9y2II79cpPC3ie7lrHCmYcMWMsoTId' \
     --header 'content-type: application/json' \
     --data '
{
  "redirect_success": "my-app://brokerage/id/success",
  "redirect_failure": "my-app://brokerage/id/failure"
}
'

The response will look like this:

{
  "url": "https://test.webid-solutions.de/service/index/cn/000671/aid/163668305",
  "video_ident_id": "163668305"
}

We will take the url property from the response object and present it to the user in the next step.

For more details, see our API reference:
Start Identity Verification.

Perform Identity Verification

In order to guide the user to the video identification process, there are two approaches:

  1. A web-based app will issue a redirect to the URL and wait for the user to return to the onboarding flow.
  2. A mobile app will open a browser, e.g. an in-app browser. The app will then wait for a success/failure callback and continue the process.

Set Experience Profile

After passing the identity verification, we will submit the user's knowledge and experience profile, so the brokerage
platform and perform the required appropriateness checks before accepting orders.

curl --request POST \
     --url https://sandbox.api.lemon.markets/v1/accounts/cusa_c2c3f89ec0524b6e818ce00c16e4897f/experience \
     --header 'LMG-Data-Privacy-Access-Justification: onboarding.knowledge_and_experience' \
     --header 'LMG-Data-Privacy-Access-Principal: backend-cusa_c2c3f89ec0524b6e818ce00c16e4897f' \
     --header 'accept: application/json' \
     --header 'authorization: Bearer lP9y2II79cpPC3ie7lrHCmYcMWMsoTId' \
     --header 'content-type: application/json' \
     --data '
{
  "stocks": {
    "experience": "none",
    "knowledge": "none"
  },
  "investment_funds": {
    "experience": "none",
    "knowledge": "none"
  }
}
'

Once all of this is in place, the account should be opened soon.

For more details, see our API reference:
Set Experience Profile.

Wait for all Checks to Complete

In order to detect when the account opening process was successful, you can issue periodic calls to inspect the
onboarding checks as outlined below. To avoid the downside of making the user wait longer than required, we recommend
to set up a webhook handler which can notify the application once the account.created event arrives for the account ID.

Query the New Account

After the account was opened, you can check the full metadata for the account, including the information required to
make a deposit.

curl --request GET \
     --url https://sandbox.api.lemon.markets/v1/accounts/cusa_c2c3f89ec0524b6e818ce00c16e4897f \
     --header 'LMG-Data-Privacy-Access-Justification: onboarding.display_cash_account' \
     --header 'LMG-Data-Privacy-Access-Principal: backend-cusa_c2c3f89ec0524b6e818ce00c16e4897f' \
     --header 'accept: application/json' \
     --header 'authorization: Bearer lP9y2II79cpPC3ie7lrHCmYcMWMsoTId'

This will provide you with the following data points:

{
  "id": "cusa_20323d55bb264d42b0b225d293591049",
  "cash_account": {
    "bic": "BYLADEM1001",
    "iban": "DE02120300000000202051"
  },
  "customer": {
    …
  },
  "declaration_of_acting_on_own_account": true,
  "history": [
    {
      "status": "opened",
      "timestamp": "2023-06-12T17:34:27.865542+00:00"
    },
    {
      "status": "created",
      "timestamp": "2023-06-12T17:23:16.975969+00:00"
    }
  ],
  "securities_account": {
    "number": "000000044"
  },
  "status": "opened"
}

You can see the status changed to opened, the history has a second element and the cash account property is populated.

For more details, see our API reference: Get Account.

Sequence Diagram

Congratulations to completing this tutorial. Here's a simplified schema of the process that can help you when
implementing this process in your product.

Sequence Diagram for Account Onboarding