As a regulated investment firm, we are required that the investors' identities are verified in a compliant manner. We rely on you to perform the identity verification during your user onboarding flow, typically via an online KYC provider.
Additionally, your customers must explicitly agree to our service agreements covering data processing and investment registry.
We recommend that you send us only approved customers, meaning that you ideally send them to us only after they have received final approval for investing.
Once these steps are complete in your system, submit the verified customer's KYC data using the following request:
Post Customer KYC /api/external/v1/customers/{customerId}/kyc
Note: This includes
tanganyLegalPerson, including its nested details at.related[]that are passed on each call).
Request Example:
# UAT BASE_URL: https://uat.api.nyala.de
# Production BASE_URL: https://api.nyala.de
# The {customerId} is 42557ea2-8a55-4599-85b2-2a91f343a08b
curl -X POST {{BASE_URL}}/api/external/v1/customers/42557ea2-8a55-4599-85b2-2a91f343a08b/kyc \
-H "Content-Type: application/json" \
-H "Authorization: HMAC YOUR_API_KEY:GENERATED_SIGNATURE" \
-H "Content-Length: CALCULATED_CONTENT_LENGTH" \
-d '{
"salutation": "Mr",
"firstname": "{{customer_random_firstname}}",
"lastname": "{{customer_random_lastname}}",
"dateOfBirth": "1985-03-20T00:00:00Z",
"placeOfBirth": "Germany",
"phoneNumber": "+493012345678",
"type": "Person",
"countryIso": "DE",
"nationalityIso": "DE",
"gender": "Male",
"email": "{{customer_random_email}}",
"taxId": "823048955",
"nonPepPerson": true,
"highCorruptionIndex": false,
"nonSanctionedCountry": true,
"nonUsTaxPerson": true,
"identVerified": true,
"identVerifiedType": "Normal",
"eulaAgreed": true,
"address": {
"street": "Uhlandstrasse",
"streetNo": "32",
"postalCode": "10719",
"town": "Berlin",
"countryCodeIso2": "DE"
},
"custodyProvider": "Tangany",
"tanganyIdentVerifiedType": "Qes_bankident",
"document": {
"country": "GB",
"nationality": "GB",
"number": "GB123456789",
"issuedBy": "Home Office Identify & Passport Service",
"issueDate": "2010-04-11",
"validUntil": "2025-04-11",
"type": "id_card",
"iban": "DE41500105177679228624",
"reference": "Ref1"
}
}'
# For example, with mock ids, and for a legal entity please use your own ids:
{
"type": "LegalEntity",
"firstname": "Marc",
"lastname": "ell Test",
"salutation": "Mr",
"email": "{{customer_email}}",
"phoneNumber": null,
"dateOfBirth": "2000-01-01T00:00:00Z",
"placeOfBirth": "Germany",
"street": "Guter Weg",
"streetNo": "12",
"postalCode": "60433",
"town": "Frankfurt am Main",
"countryIso": "DE",
"nationalityIso": "DE",
"custodyProvider": 1,
"gender": "Male",
"company": {
"name": "CONCEDUS GmbH",
"registerNumber": "HRB 45003",
"fullAddress": "Ostendstr. 100, 90482 Nürnberg, DE",
"email": "{{customer_email}}"
},
"address": {
"street": "street",
"streetNo": "32",
"postalCode": "9899",
"town": "laketown",
"countryCodeIso2": "DE"
},
"document": {
"country": "DE",
"nationality": "DE",
"number": "DE123456789",
"issuedBy": "Home Office Identify & Passport Service",
"issueDate": "2010-04-11",
"validUntil": "2025-04-11",
"type": "id_card",
"iban": "DE00000000001234",
"reference": "Ref1"
},
"tanganyLegalPerson": {
"id": "af792bc3-b9d0-4e55-a179-0ae8db7905f7",
"name": "CONCEDUS GmbH",
"legalForm": "GmbH",
"commercialRegister": "Amtsgericht Nürnberg",
"leiCode": "12345678911",
"taxId": "12345678911",
"vatId": "12345678911",
"isincode": "12345678911",
"legalJurisdiction": "DE",
"legalAddress": {
"country": "DE",
"city": "Nürnberg",
"postcode": "90482",
"streetName": "Ostendstr.",
"streetNumber": "100"
},
"postalAddress": {
"country": "DE",
"city": "Nürnberg",
"postcode": "90482",
"streetName": "Ostendstr.",
"streetNumber": "100"
},
"kyc": {
"businessDescription": "Investor",
"isCreAvailable": false
},
"related": [
{
"position": "CEO",
"isFictitiousBeneficialOwner": false,
"isUltimateBeneficialOwner": true,
"sharePercentage": "30"
},
{
"position": "CEO",
"isFictitiousBeneficialOwner": false,
"isUltimateBeneficialOwner": false,
"sharePercentage": "21",
"naturalPerson": {
"id": "ff0b20e8-fc79-4530-8c6d-1816f2d71a3a",
"firstName": "Johny5",
"lastName": "English5",
"birthDate": "2000-01-01T00:00:00Z",
"birthPlace": "Berlin5",
"title": "Mr",
"gender": null,
"birthCountry": "DE",
"birthName": "English5",
"nationality": "DE",
"address": {
"country": "DE",
"city": "Berlin5",
"postcode": "34567",
"streetName": "Str",
"streetNumber": "2"
},
"email": "a5@example.com",
"selfDeclaredAsPep": false,
"kyc": {
"id": "14670653-a203-4f09-ba0b-ef600f5c9bf4",
"date": "2025-01-07T12:15:00.2621965+01:00",
"method": "in_person",
"document": null
}
}
},
{
"position": "CEO",
"isFictitiousBeneficialOwner": false,
"isUltimateBeneficialOwner": false,
"sharePercentage": "22",
"naturalPerson": {
"id": "86398969-a58c-4798-b234-734146cfc549",
"firstName": "Johny6",
"lastName": "English6",
"birthDate": "2000-01-01T00:00:00Z",
"birthPlace": "Berlin6",
"title": "Mr",
"gender": null,
"birthCountry": "DE",
"birthName": "English6",
"nationality": "DE",
"address": {
"country": "DE",
"city": "Berlin6",
"postcode": "34567",
"streetName": "Str",
"streetNumber": "2"
},
"email": "a6@example.com",
"selfDeclaredAsPep": false,
"Kyc": {
"id": "ba951d45-aaec-4b06-81c3-d8944ba20054",
"date": "2025-01-07T12:15:00.2621965+01:00",
"method": "in_person",
"document": null
}
}
}
]
}
}
# The related entity array works as follows:
"related": [
{
"position": "CEO",
"isFictitiousBeneficialOwner": false,
"isUltimateBeneficialOwner": true,
"sharePercentage": "30"
}, -> First Entry referring to the original person "firstname": "Marc", "lastname": "ell Test",
{
"position": "CEO",
"isFictitiousBeneficialOwner": false,
"isUltimateBeneficialOwner": false,
"sharePercentage": "21",
"naturalPerson": {
"id": "ff0b20e8-fc79-4530-8c6d-1816f2d71a3a",
"firstName": "Johny5",
"lastName": "English5",
"birthDate": "2000-01-01T00:00:00Z",
"birthPlace": "Berlin5",
"title": "Mr",
"gender": null,
"birthCountry": "DE",
"birthName": "English5",
"nationality": "DE",
"address": {
"country": "DE",
"city": "Berlin5",
"postcode": "34567",
"streetName": "Str",
"streetNumber": "2"
},
"email": "a5@example.com",
"selfDeclaredAsPep": false,
"kyc": {
"id": "14670653-a203-4f09-ba0b-ef600f5c9bf4",
"date": "2025-01-07T12:15:00.2621965+01:00",
"method": "in_person",
"document": null
}
}
}, -> Second Entry new entity that will be created on Tangany
{
"position": "CEO",
"isFictitiousBeneficialOwner": false,
"isUltimateBeneficialOwner": false,
"sharePercentage": "22",
"naturalPerson": {
"id": "86398969-a58c-4798-b234-734146cfc549",
"firstName": "Johny6",
"lastName": "English6",
"birthDate": "2000-01-01T00:00:00Z",
"birthPlace": "Berlin6",
"title": "Mr",
"gender": null,
"birthCountry": "DE",
"birthName": "English6",
"nationality": "DE",
"address": {
"country": "DE",
"city": "Berlin6",
"postcode": "34567",
"streetName": "Str",
"streetNumber": "2"
},
"email": "a6@example.com",
"selfDeclaredAsPep": false,
"kyc": {
"id": "ba951d45-aaec-4b06-81c3-d8944ba20054",
"date": "2025-01-07T12:15:00.2621965+01:00",
"method": "in_person",
"document": null
}
}
} -> Third Entry new entity that will be created on Tangany
]The following parameters apply to KYC data for both natural person and legal entity investors. For legal entities, all KYC data pertains to the company representative performing the KYC verification.
| Parameter | Description | Expected Values |
|---|---|---|
| taxID | The unique identifier of the customer towards the tax authorities of their country of the residence. It can be called tax ID, Steuernummer, or something else depending on the country. We only need it to process payments for co-listing projects, in which case it becomes necessary (so we can withhold and pay the tax). | "8204322532" |
| placeOfBirth | Place of birth denoted in the used identification document of the investor. | "Berlin" |
| nonPepPerson | Relates to the political exposure of the person. Indicates whether the person is NOT a Politically Exposed Person (PEP). A PEP customer is not automatically rejected by our system. If we receive a PEP, our system will flag it and we will perform enhanced due diligence, after which we may let the person through to authorize opt-ins and token distributions. | true |
| highCorruptionIndex | Relates to the country of residence. You can always send "false" if your KYC provider performs these checks automatically. If you send the value "true", our system will flag it and we will perform enhanced due diligence. | false |
| nonSanctionedCountry | Indicates the investor is NOT residing in a sanctioned country. You can always send "true" if your KYC provider performs these checks automatically. If you send the value "false", our system will flag it and we will perform enhanced due diligence. | true |
| nonUsTaxPerson | We do not accept persons subjected to US tax. Always set to "true" (if the person is not subject to taxes in the USA). | true |
| identVerified | Only send KYC data of customers that have been verified already. Hence, always set this field to "true". | true |
| identVerifiedType | Legacy field. You can ignore and leave blank. | |
| tanganyIdentVerifiedType | Only relevant when custodian is set to Tangany. Type of KYC process depends on your active markets and your own provider. See detailed verification type description in the table Tangany Identity Verification Type Description. | "Video_ident", "Id_copy", "Auto_ident", "In_person", "Eid", "Post_ident", "Qes_bankident" |
| eulaAgreed | Refers to the Smart Registry terms of use. Ensure that your end users always have to agree to the terms as part of their onboarding process, then always set to "true". | true |
The table below describes document parameters used for KYC verification. A document is required for all verification methods except in_person when Tangany is the chosen custodian.
| Parameter | Description | Expected Values |
|---|---|---|
| document.nationality | Stated nationality. Must be a ISO 3166-1 Alpha-2 country code. Additionally "XX" is allowed for unknown states. | "DE" |
| document.country | Document issuing country. Must be a ISO 3166-1 Alpha-2 country code. Additionally "XX" is allowed for unknown states. | "DE" |
| document.number | ID number of the document. | "C01X00T47" |
| document.issuedBy | Name of the document issuer. | "Stadt Berlin" |
| document.issueDate | Date of issuance in the format YYYY-MM-DD. Must be >= 1900-01-01. If not provided, can be set to n/a. | "2020-01-15" |
| document.validUntil | Stated expiration date of the document in the YYYY-MM-DD format. Must be >= 1900-01-01. | "2030-01-15" |
| document.type | Type of the document. | "Id_card", "Passport", "Other" |
| document.iban | International Bank Account Number comprised of maximum 34 characters, letters and numbers. | "DE89370400440532013000" |
| document.reference | Reference or purpose of a transfer containing any characters. Nullable for all methods except QES_bankident (tanganyIdentVerifiedType). | "Reference text" |
The table below describes address parameters (nested under address) for the legal entity's representative.
| Parameter | Description | Expected Values |
|---|---|---|
| address.street | Street name of the representative's address. | "Uhlandstraße" |
| address.streetNo | Street number of the representative's address. | "32" |
| address.postalCode | Postal code of the representative's address. | "10719" |
| address.town | Town of the representative's address. | "Berlin" |
| address.countryCodeIso2 | ISO country code (e.g. "DE"). | "DE" |
Please send the method that applies to your process:
| Verification Type | Process Description |
|---|---|
| Video Ident | The Investor provides personal information, then participates in a live video call with a trained agent. A valid ID document and mobile phone number are required. The Investor confirms identity via SMS TAN to complete the process. Video_ident works with standard structured identity data. Qes_bankident additionally requires iban and reference in the document object, or it returns an error code 400. |
| Id_copy / Remote Identification | The Investor photographs their ID document and face, then uploads images to the platform. Verification is completed without third-party KYC provider involvement. |
| Auto_ident | The Investor provides personal information and photographs of the front and back of their ID document. An automated video captures the investor's face, which is then compared to the ID document through AI-based verification. The process is fully automated without real-time agent interaction, though automated quality checks may be applied. |
| eID | The Investor installs a KYC provider app on their NFC-enabled smartphone. The app reads electronic data from a German identity card or residence permit using NFC technology. A 6-digit PIN is required for the Online ID feature to complete the process. |
| Post_ident | The Investor visits a Deutsche Post branch location for in-person identity verification. A postal employee scans the ID document, verifies it against the person present, and confirms the identity data. The investor signs electronically to complete the process. Verification data is transmitted digitally to the requesting company. |
| Qes_bankident | This is also called the qualified signature process. The KYC provider identifies the investor via VideoID or AccountID (using online banking credentials). Investor confirms via TAN, reviews the contract, and signs it with a final TAN signature to complete identification. |
| In_person | The Investor visits the client's branch or office location for face-to-face identity verification. A trained employee of the obliged entity (bank, financial institution, or platform) examines the original ID document, compares the photo with the person present, and verifies identity data. The employee documents the verification process according to regulatory requirements. |
When applicable the full
tanganyIdentVerifiedTypeenum, is composed of:Video_ident,Id_copy,Auto_ident,In_person,Eid,Post_ident,Qes_bankidentfor most cases.The full
identVerifiedTypeenum is:NotSet,Normal,Plain.
Response Example:
{
"errorMessageCodes": null,
"errors": null,
"data": true
}The parameters in the following tables are relevant only if Tangany is selected as the custodian.
The table below describes some parameters regarding Tangany legal entity (nested under tanganyLegalPerson).
| Parameter | Description | Expected Values |
|---|---|---|
| tanganyLegalPerson.id | A UUID for the company. | UUID value |
| tanganyLegalPerson.name | The name of the company. You can re-use the value from company.name. | "ACME Corporation GmbH" |
| tanganyLegalPerson.legalForm | Legal form of company. E.g. "AG", "GmbH". | "GmbH", "AG" |
| tanganyLegalPerson.commercialRegister | You may leave it blank. Legally speaking, only the register number is required. | "Amtsgericht Berlin" |
| tanganyLegalPerson.leiCode | LEI code of the company. | "549300ABCDEFGHIJK123" |
| tanganyLegalPerson.taxId | Tax ID of the company. | "12/345/67890" |
| tanganyLegalPerson.vatId | Vat ID of the company. | "DE123456789" |
| tanganyLegalPerson.isincode | ISIN code of the company. | "DE0005140008" |
| tanganyLegalPerson.legalJurisdiction | ISO country code (e.g. "DE") where the legal entity is registered. Not mandatory, as this data is captured within the legalAddress object. | "DE" |
The table below describes some parameters regarding Tangany legal entity (nested under 'tanganyLegalPerson.legalAddress).
| Parameter | Description | Expected Values |
|---|---|---|
| legalAddress.country | ISO country code (e.g. "DE") where the company is registered. | "DE" |
| legalAddress.city | City where company is registered. | "Berlin" |
| legalAddress.postcode | Post code where company is registered. | "10115" |
| legalAddress.streetName | Street name where company is registered. | "Hauptstrasse" |
| legalAddress.streetNumber | Street number where company is registered. | "10" |
The table below describes some parameters regarding Tangany legal entity (nested under 'tanganyLegalPerson.postalAddress).
| Parameter | Description | Expected Values |
|---|---|---|
| postalAddress.country | You may re-use the same data as for the legal address. | "DE" |
| postalAddress.city | You may re-use the same data as for the legal address. | "Berlin" |
| postalAddress.postcode | You may re-use the same data as for the legal address. | "10115" |
| postalAddress.streetName | You may re-use the same data as for the legal address. | "Hauptstrasse" |
| postalAddress.streetNumber | You may re-use the same data as for the legal address. | "10" |
The table below describes some parameters regarding Tangany legal entity (nested under 'tanganyLegalPerson.kyc).
| Parameter | Description | Expected Values |
|---|---|---|
| kyc.businessDescription | You can always send the following value: "Investor". | "Investor" |
| kyc.isCreAvailable | You can always set this field to "false". | false |
The table below describes some parameters regarding Tangany legal entity (nested under 'tanganyLegalPerson.related).
| Parameter | Description | Expected Values |
|---|---|---|
| related.entityId | The legal requirement is to create one per beneficial owner of the company (even if they do not have to go through the KYC process). Do not supply an entityId when creating new beneficial owners. | UUID of beneficial owner |
| related.position | Position of the beneficial owner in the company. Takes any string needed. | "CEO", "Director" |
| related.isFictitiousBeneficialOwner | Indicates if this is a fictitious beneficial owner. | false |
| related.isUltimateBeneficialOwner | Indicates if this is the ultimate beneficial owner. | true |
| related.sharePercentage | Share percentage of ownership. Passed as a string "str" | "25.5", "100" |
Response Example: In response to the successful user creation, you will receive a user ID, which you will need to proceed with the saving of the KYC data, the wallet creation request, and more.
{
"errorMessageCodes": null,
"errors": null,
"data": "42557ea2-8a55-4599-85b2-2a91f343a08b"
}| Case | Error code | Example response |
|---|---|---|
| Invalid customer ID | 500 | "title": "An error occurred while processing your request.","status": 500 |
| Validation errors on specific fields (e.g. first name missing) | 400 | "title": "One or more validation errors occurred.","status": 400, "errors": {"Firstname": ["The Firstname field is required."] |