Introduction
Welcome to the Penneo KYC Public API. You can use our API to access our system via GraphQl, which can retrieve information on various cases, documents and clients from your organisation.
You can view code examples in the dark area to the right.
To use GraphQL, you must use the https://api.prod.kyc.penneo.com/public-api/graphql
endpoint.
They must be formatted correctly for graphql with query
, variables
and mutation
fields if used.
We recommend using postman to try things out and copying the request as you preferred code using their built-in tools.
Remember to add the Authorization headers and X-API-Version
-header with the appropriate version.
Versioning
The version is passed as part of the X-API-Version header
curl "api_endpoint_here"
--header 'X-API-Version: 1'
var myHeaders = new Headers();
myHeaders.append("X-API-Version", "1");
var formdata = new FormData();
var requestOptions = {
method: 'GET',
headers: myHeaders,
body: formdata,
redirect: 'follow'
};
fetch("https://api.prod.kyc.penneo.com/public-api/graphql", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
The entire API, including the Authorize-endpoint, and GraphQL endpoints are versioned.
The version is required on every request, and must be provided via the X-API-Version
-header.
Supported versions
Version | Release date | Deprecation date |
---|---|---|
1 | 01-06-2020 | 6 months after version 2 |
Schema
You can find the entire graphql schema at:
https://api.prod.kyc.penneo.com/public-api/graphql/schema?version=1
Authentication
AccessId and AccessKey
To use the API you need a set of AccessId and AccessKey. They are obtained from within our application, in your settings, under “API Adgang“. If you cannot find this area in your settings, please contact support. They will be able to enable API access for you.
In the “API Adgang“-area you can press the button to obtain a new set of AccessId & AccessKey.
If you lose the key you can delete the Access Keypair via the “API Adgang“-area, where they are listed. The ID-variable corresponds to the AccessId in the list.
Authorization token
To get a token for the Authorization header, use this endpoint:
curl --location --request POST 'https://api.prod.kyc.penneo.com/public-api/authorize?accessId=<ACCESS-ID>&accessKey=<ACCESS-KEY>' \
--header 'X-API-Version: 1' \
--header 'Content-Type: application/javascript'
var myHeaders = new Headers();
myHeaders.append("X-API-Version", "1");
myHeaders.append("Content-Type", "application/javascript");
var formdata = new FormData();
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: formdata,
redirect: 'follow'
};
fetch("https://api.prod.kyc.penneo.com/public-api/authorize?accessId=<ACCESS-ID>&accessKey=<ACCESS-KEY>", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
The endpoint returns a JSON object with this structure:
{
"token": "abcdefghijklmnopqrstuvwxyz",
"timeExpiration": "2020-01-01T00:00:00+00:00"
}
The API is accessed via a Bearer token. This token is a standard JSON Web Token that is sent along with every request to our API via the Authorization-header. The token expires in 15 minutes, after which a new token must be obtained. It is recommend that you set up a way to automatically renew tokens when they expire if doing operations that span over 15 minutes.
To obtain a token you must use the authorize-endpoint:
POST https://api.prod.kyc.penneo.com/public-api/authorize?accessId=<ID>&accessKey=<KEY>
Parameter | Description |
---|---|
accessId | The ID of the Access Keypair |
accessKey | The Key of the Access Keypair |
Using the token
The Authorization header, must be included on every request and be formatted as Bearer
:
curl --location --request POST 'https://api.prod.kyc.penneo.com/public-api/grapqhl' \
--header 'X-API-Version: 1' \
--header 'Authorization: Bearer <TOKEN>' \
--header 'Content-Type: application/json'
var myHeaders = new Headers();
myHeaders.append("X-API-Version", "1");
myHeaders.append("Authorization", "Bearer <TOKEN>");
myHeaders.append("Content-Type", "application/json");
var formdata = new FormData();
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: formdata,
redirect: 'follow'
};
fetch("https://api.prod.kyc.penneo.com/public-api/graphql", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
# The Authorization header is used on the request to the /graphql endpoint
You simply include the token in the Authorization header on every request, along with the X-API-Version
-header.
Authorization: Bearer <YOUR-TOKEN>
Shared data types
The API uses custom data types which are not present in standard graphql:
Simple types
Timestamp
A UNIX timestamp version of a date and time. The value is in milliseconds.
Chunks
Json representation of a Chunk.
{
"id": "12345678",
"payload": "35633766",
"payloadSize": 8,
"mimeType": "text/plain",
"subType": "ExternalId/DK/CVR/Number",
"acceptance": "accepted",
"timeCreated": 12345678,
"timeLastEdited": 12345678
}
Chunks are a generic type that most data in the API is based on, they all contain a type, and a subtype and the value is stored in the payload field. The payloads may be a file, for such cases the mimetype is included in the output.
The chunks have an acceptance value that indicates the acceptance status of a particular chunk.
Possible values for acceptance
-field
accepted
rejected
pending
expired
For information on reading chunks from Companies and Persons, check under their section in the menu.
ExternalId_DK_CPR_Number
The CPR number in Denmark of a person
ExternalId_DK_CVR_Number
The VAT number in Denmark of the company
ExternalId_DK_CVR_APIId
The ApiId in the Danish VAT registry of the company or person
ExternalId_Vendor_Economic_CustomerNumber
An identifier in Economic for this a company or person
ContactInfo_Email
The contact email of a company or person
ContactInfo_Phone
The contact phonenumber of a company or person
IdentityValidationToken_DKNemIDCPR
An identity validation token from the danish NemID system.
Document
A document that has either been user-defined or defined by the system, could be a passport or a driving license.
ListCheck
A record of when we checked various PEP and sanctions lists for the name of the company or person.
Info Types
Info types describe a person or company that may or may not already exist in our database.
PersonInfo
Json representation of PersonInfo. You only need to supply one of the following pieces of information:
{
"Name": "FirstName Lastname",
"ExternalId_DK_CVR_APIId": ["XXXXXX"],
"ExternalId_DK_CPR_Number": ["XXXXXXXX"],
"ContactInfo_Email": ["XXXXXX"],
"ContactInfo_Phone": ["XXXXXX"],
"ExternalId_GenericCustomerNumber": ["XXXXXX"],
"ExternalId_Vendor_Economic_CustomerNumber": ["XXXXXX"]
}
All fields in info, except Name, accepts multiple values.
You only need to supply one of these, but you should add all the info you can.
Field | Description |
---|---|
Name | The name of the person |
ExternalId_DK_CVR_APIId | The ApiId in the Danish VAT registry of the person, can be several |
ExternalId_DK_CPR_Number | The CPR number in Denmark of a person |
ContactInfo_Email | The contact email of the person, can be several |
ContactInfo_Phone | The contact phonenumber of the person, can be several |
ExternalId_GenericCustomerNumber | An identifier in your own system for this person, can be several |
ExternalId_Vendor_Economic_CustomerNumber | An identifier in your Economic system for this person, can be several |
CompanyInfo
Json representation of CompanyInfo. You only need to supply one of the following pieces of information:
{
"Name": "My Company Client",
"ExternalId_DK_CVR_Number": ["XXXXXXXX"],
"ExternalId_DK_CVR_APIId": ["XXXXXX"],
"ContactInfo_Email": ["XXXXXX"],
"ContactInfo_Phone": ["XXXXXX"],
"ExternalId_GenericCustomerNumber": ["XXXXXX"],
"ExternalId_Vendor_Economic_CustomerNumber": ["XXXXXX"],
"ExternalId_Vendor_DunBradstreet_DUNSNumber": ["XXXXXX"],
"ExternalId_NO_BusinessRegistrationNumber": ["XXXXXX"],
"ExternalId_GenericBusinessRegistrationNumber": [
{
"countryCode": "DK",
"registrationNumber": "XXXXXX"
}
]
}
All fields in info, except Name, accepts multiple values.
You only need to supply one of these, but you should add all the info you can.
Field | Description |
---|---|
Name | The name of the company |
ExternalId_DK_CVR_Number | The VAT number in Denmark of the company, can be several |
ExternalId_DK_CVR_APIId | The ApiId in the Danish VAT registry of the company, can be several |
ContactInfo_Email | The contact email of the company, can be several |
ContactInfo_Phone | The contact phonenumber of the company, can be several |
ExternalId_GenericCustomerNumber | An identifier in your own system for this company, can be several |
ExternalId_Vendor_Economic_CustomerNumber | An identifier in your Economic system for this client, can be several |
ExternalId_Vendor_DunBradstreet_DUNSNumber | A DUNS number from DunBradstreet, can be several |
ExternalId_NO_BusinessRegistrationNumber | A Norwegian Business Registration Number, can be several |
ExternalId_GenericBusinessRegistrationNumber | A generic business number, you must supply both a country code and a registration number, can be several |
Filtering
Each type filter is defined by its type, e.g. CaseFilters:
query getCases($amount: Int, $filters: [CaseFilters]) {
cases(amount: $amount, filters: $filters) {
items {
item {
id
name
}
}
}
}
variables: {
filters: {
{ name: { equals: "test" } }
}
}
We get the elements that matches the filter:
{
"data": {
"cases": {
"items": [
{
"item": {
"name": "test"
}
},
{
"item": {
"name": "test"
}
}
],
}
}
}
The Public API has a powerful filtering system.
It allows you to filter either Cases, Companies or Persons.
The filtering system is currently only available for use with GraphQL.
In the code example to the right, you can see how a basic use of it looks. Here we are filtering cases for any case named "test".
The syntax of these filters allows each field to have multiple filters.
The operators are string based and can be seen alongside the filter definitions.
The various filters are described underneath:
CaseFilters
Name | Type | Supported operators |
---|---|---|
name | String | equals , notEquals |
timeCreated | Integer | equals , notEquals , lessThan , greaterThan |
timeLastEdited | Integer | equals , notEquals , lessThan , greaterThan |
externalId | String | This has a special set of operators, and is explained in the next section. It looks up the related Persons and Companies as the cases do not have any externalIds. |
CompanyFilters
Name | Type | Supported operators |
---|---|---|
name | String | equals , notEquals |
timeCreated | Integer | equals , notEquals , lessThan , greaterThan |
timeLastEdited | Integer | equals , notEquals , lessThan , greaterThan |
externalId | String | This has a special set of operators, and is explained in the next section |
PersonFilters
Name | Type | Supported operators |
---|---|---|
name | String | equals , notEquals |
timeCreated | Integer | equals , notEquals , lessThan , greaterThan |
timeLastEdited | Integer | equals , notEquals , lessThan , greaterThan |
externalId | String | This has a special set of operators, and is explained in the next section |
Special case: ExternalId
Again the filter syntax is almost the same, except for the externalId name and having two operators:
query getPersons($amount: Int, $filters: [PersonFilters]) {
persons(amount: $amount, filters: $filters) {
items {
item {
id
name
ExternalId_Vendor_Advosys_CustomerNumber
}
}
}
}
variables {
filters: {
{ externalId: { type: "ExternalId_Vendor_Advosys_CustomerNumber", in: ["1", "2", "3"] } }
}
}
We get the elements that matches the filter:
{
"data": {
"persons": {
"items": [
{
"item": {
"name": "test",
"ExternalId_Vendor_Advosys_CustomerNumber": ["1"]
}
},
{
"item": {
"name": "test",
"ExternalId_Vendor_Advosys_CustomerNumber": ["2"]
}
},
{
"item": {
"name": "test",
"ExternalId_Vendor_Advosys_CustomerNumber": ["3"]
}
}
]
}
}
}
The ExternalId filter allows API users to query cases persons or companies based on an id that is from another external system, like CVR or e-conomic.
It takes two operators that must both be present, the type
, which is a string and an in
-selection, which is an array of strings or integers.
Only Persons and Companies have ExternalIds. When filtering with this on cases, it looks into the related Persons and Companies of that case, and returns the case if matching relations were found.
Underneath you can see the ExternalIds that are currently supported by the API and the system:
Name | Description |
---|---|
ExternalId_Vendor_Advosys_CustomerNumber | A customer number from the Unik Advosys System |
ExternalId_Vendor_Economic_CustomerNumber | A customer number from Visma e-conomic |
ExternalId_DK_CVR_APIId | The unique id in the CVR API for this item |
ExternalId_DK_CVR_Number | The CVR number of a company. |
Cases
Data model for cases
query {
type Case implements Node {
id: ID!
name: String
timeCreated: Timestamp!
timeLastEdited: Timestamp!
url: String
status: String
detailedStatus: String
statusText: LocalizedSet
clients(
# Sets the amount of items to return. Defaults to 10
amount: Int
# The cursor of a previously returned item. The items returned will be ones listed before this cursor.
before: String
# The cursor of a previously returned item. The items returned will be ones listed after this cursor.
after: String
): [Clients]
AMLPersons(
# Sets the amount of items to return. Defaults to 10
amount: Int
# The cursor of a previously returned item. The items returned will be ones listed before this cursor.
before: String
# The cursor of a previously returned item. The items returned will be ones listed after this cursor.
after: String
): [Person]
contactPersons(
# Sets the amount of items to return. Defaults to 10
amount: Int
# The cursor of a previously returned item. The items returned will be ones listed before this cursor.
before: String
# The cursor of a previously returned item. The items returned will be ones listed after this cursor.
after: String
): [Person]
documents: [Document]
riskAssessmentConclusion: RiskAssessmentConclusion
riskAssessmentAnswers: [SimpleRAAnswer]
}
}
You can see the datamodel for cases to the right.
The url is the url in the administration panel for this case.
The status is an enum-ish value of the current ultimate status. The detailedStatus is a more detailed status, still represented as an enum-ish value. The statusText is a localized string, (currently only available in danish), that translates the detailedStatus.
The possible values are listed below:
status | detailedStatus | Danish statusText |
---|---|---|
FULFILLED | fulfilled | No text on this one |
CONTACTED | contacted | Can be either '1 person kontaktet' or '(number) personer kontaktet' |
PENDING | noClient | Mangler klient |
PENDING | noOwners | Mangler reelle ejere |
PENDING | noApproval | Bekræft ejerforhold, før du fortsætter |
PENDING | noRiskAssessment | Mangler risikovurdering |
PENDING | updateConclusion | Konklusion bør opdateres |
PENDING | chunksPending | Dokumenter afventer godkendelse |
PENDING | awaitingContact | Afventer kontakt |
PENDING | abandonedContactPoint | Kontaktet, men har ikke svaret |
Create case
mutation CreateCase($preset: String!) {
createCase(preset: $preset) {
id
name
timeCreated
timeLastEdited
}
}
variables {
preset: "somePreset"
}
Adding a case returns the following:
{
"id": "abcdefg",
"name": null,
"timeCreated": 12345678,
"timeLastEdited": 12345678
}
This mutation adds a case.
Variables
The preset variable does not do anything yet, and can be left out.
Variable | Description |
---|---|
Preset | The name of the a preset to use for this case, it is optional. |
Get all Cases
query getCases($amount: Int) {
cases(amount: amount) {
items {
item {
id
name
}
cursor
}
totalCount
pageInfo {
hasPreviousPage
beforeCursor
hasNextPage
afterCursor
}
}
}
variables {
amount: 10,
}
This query retrieves all cases.
This query is paginated. You can learn more about how this works in the Pagination section.
Get a case by ID
query getCase($id: ID) {
case(id: $id) {
id
name
timeCreated
timeLastEdited
}
}
variables {
id: ID,
}
This query retrieves a specific case.
Variables
Variable | Description |
---|---|
ID | The ID of the case to retrieve |
Risk-assessments
Add risk-assessment conclusion to case
mutation SetRiskAssessmentConclusion($caseId: ID, $conclusion: RiskAssessmentConclusion!, $notes: String) {
setRiskAssessmentConclusion(caseId: $caseId, conclusion: $conclusion, notes: $notes) {
id
name
riskAssessmentConclusion
timeCreated
timeLastEdited
}
}
variables {
caseId: "<CASE-ID>",
conclusion: "LOW",
notes: "My optional note"
}
This mutation adds a risk-assessment conclusion to a case. It requires a caseId and a RiskAssessmentConclusion. Optionally you can add a note as well.
Variables
Variable | Description |
---|---|
caseId | The id of the case. |
conclusion | The conclusion of the risk-assessment. See possible values below |
Notes | A note explaining the risk-assessment, it is optional. |
Possible RiskAssessmentConclusion values
The preset variable does not do anything yet, and can be left out.
Value | Description |
---|---|
UNKNOWN | Used to set an unknown risk assessment. |
LOW | Used to set a low risk assessment. |
MEDIUM | Used to set a medium risk assessment |
HIGH | Used to set a high risk assessment |
Companies
You can see the data model for companies to the right.
Data model for companies
query {
type Company implements Node {
id: ID!
name: String
timeCreated: Timestamp!
timeLastEdited: Timestamp!
url: String
beneficialOwners: [Person]!
legalOwners: [LegalOwners]
executives: [Person]!
ceo: [Person]!
fullyResponsibleParticipants: [Person]!
boardMembers: [Person]!
boardChairman: [Person]!
documents: [Document]
ContactInfo_Email: [Email]
ContactInfo_Phone: [PhoneNumber]
CompanyInformation_Status: [Status]
CompanyInformation_Type: [Type]
CompanyInformation_PowerToBind: [PowerToBind]
IdentityValidationToken: [IdentityValidationToken]
ExternalId_Vendor_Economic_CustomerNumber: [EconomicCustomerNumber]
ExternalId_Vendor_Advosys_CustomerNumber: [AdvosysCustomerNumber]
ExternalId_DK_CVR_APIId: [DKCVRAPIIdType]
ExternalId_DK_CVR_Number: [DKCVRNumber]
ExternalId_Vendor_DunBradstreet_DUNSNumber: [Vendor_DunBradstreet_DUNSNumber]
ExternalId_NO_BusinessRegistrationNumber: [NO_BusinessRegistrationNumber]
ExternalId_GenericCustomerNumber: [GenericCustomerNumber]
ExternalId_GenericBusinessRegistrationNumber: [GenericBusinessRegistrationNumber]
listChecks: [ListCheck]
latestListCheck: ListCheck
externalQuestionnaireResponses: [ExternalQuestionnaireResponse]
}
}
Add Company as a Client
mutation AddCompanyClientToCase($id: ID!, $info: CompanyInfo!) {
addCompanyClientToCase(id: $id, info: $info) {
id
name
timeCreated
timeLastEdited
}
}
variables {
id: ID,
info: See info example under "Shared data types"
}
This mutation adds a company with a relation as client to a specific case. You can set different information pieces on the client.
The system can deduce if a client already exists with the info you are adding. If so, any new information will be appended to the existing company client.
Variables
Variable | Description |
---|---|
ID | The ID of the case to add the client to |
The company info variables can be found under Shared data types
Add Owner to a Company
mutation AddOwnerToCompany($id: ID!, $info: PersonInfo!) {
addOwnerToCompany(id: $id, info: $info) {
id
name
timeCreated
timeLastEdited
}
}
variables {
id: ID,
info: See PersonInfo example under "Shared data types"
}
This mutation adds an owner to a company. The owner will always be a person. You can set different information pieces on the client.
The system can deduce if an owner already exists with the info you are adding. If so, any new information will be appended to the existing company owner.
Variables
Variable | Description |
---|---|
ID | The ID of the company to add the company to |
The PersonInfo variables can be found under Shared data types
Get all companies
query {
companies(amount: amount) {
items {
item {
id
name
}
cursor
}
totalCount
pageInfo {
hasPreviousPage
beforeCursor
hasNextPage
afterCursor
}
}
}
variables {
amount: 10,
}
This query retrieves all companies.
This query is paginated. You can learn more about how this works in the Pagination section.
Get a company by ID
query {
company(id: ID) {
id
name
timeCreated
timeLastEdited
}
}
variables {
id: ID,
}
This query retrieves a specific company.
Variables
Variable | Description |
---|---|
ID | The ID of the company to retrieve |
Get owners of a company
query getCompanyOwners($id: ID!) {
company(id: $id) {
id
name
beneficialOwners {
id
name
}
timeCreated
timeLastEdited
}
}
variables {
id: ID,
}
This query retrieves a specific company's owners.
Variables
Variable | Description |
---|---|
ID | The ID of the company to retrieve owners for |
Get chunks from a company
query getCompanyDocuments($id: ID!) {
company(id: $id) {
documents {
id
payload
subType
payloadSize
mimeType
timeCreated
timeLastEdited
}
}
}
variables {
id: ID,
}
See the Shared Data Types section for an explanation of Chunks.
Companies can have several types of Chunks associated with them. They are listed below with their Chunk type and their corresponding field on the Company type:
Type | GraphQL |
---|---|
Document | documents |
ContactInfo_Email | |
PhoneNumber | ContactInfo_Phone |
IdentityValidationToken | IdentityValidationToken |
EconomicCustomerNumber | ExternalId_Vendor_Economic_CustomerNumber |
GenericCustomerNumber | ExternalId_GenericCustomerNumber |
GenericBusinessRegistrationNumber | ExternalId_GenericBusinessRegistrationNumber |
DKCVRApiIds | ExternalId_DK_CVR_APIId |
DKCVRNumbers | ExternalId_DK_CVR_Number |
ListCheck | listChecks |
ListCheck | latestListCheck |
Variables
Variable | Description |
---|---|
ID | The ID of the company to retrieve chunks for |
Search for companies that are not already stored in the system
query($queryString: String!, $countryCode: String!) {
lookupCompany(queryString: $queryString, countryCode: $countryCode) {
items {
item {
Name
ExternalId_DK_CVR_Number
ExternalId_NO_BusinessRegistrationNumber
ExternalId_Vendor_DunBradstreet_DUNSNumber
score
}
}
totalCount
}
}
variables {
queryString: String,
countryCode: String
}
You can search for companies that the system might not already know about using the lookupCompany mutation. This will perform a search in connected systems like the Danish company registry (CVR) and, if you have an applicable subscription, Dun & Bradstreet's international company data registry.
The resulting list can be displayed to a user as a list of possible options.
Search results are effectively equivalent to a list of CompanyInfo objects, which means that a search result can be passed verbatim as input to the addCompanyClientToCase mutation.
Persons
You can see the datamodel for persons to the right.
Data model for persons
query {
person {
id: ID!
name: String
timeCreated: Timestamp!
timeLastEdited: Timestamp!
url: String
beneficialOwners: [Person]!
legalOwners: [LegalOwners]
executives: [Person]!
ceo: [Person]!
fullyResponsibleParticipants: [Person]!
boardMembers: [Person]!
boardChairman: [Person]!
documents: [Document]
ContactInfo_Email: [Email]
ContactInfo_Phone: [PhoneNumber]
CompanyInformation_Status: [Status]
CompanyInformation_Type: [Type]
CompanyInformation_PowerToBind: [PowerToBind]
IdentityValidationToken: [IdentityValidationToken]
ExternalId_Vendor_Economic_CustomerNumber: [EconomicCustomerNumber]
ExternalId_Vendor_Advosys_CustomerNumber: [AdvosysCustomerNumber]
ExternalId_DK_CVR_APIId: [DKCVRAPIIdType]
ExternalId_DK_CVR_Number: [DKCVRNumber]
ExternalId_Vendor_DunBradstreet_DUNSNumber: [Vendor_DunBradstreet_DUNSNumber]
ExternalId_NO_BusinessRegistrationNumber: [NO_BusinessRegistrationNumber]
ExternalId_GenericCustomerNumber: [GenericCustomerNumber]
listChecks: [ListCheck]
latestListCheck: ListCheck
externalQuestionnaireResponses: [ExternalQuestionnaireResponse]
}
}
Add Person as a Client
mutation AddPersonClientToCase($id: ID!, $info: PersonInfo!) {
addPersonClientToCase(id: $id, info: $info) {
id
name
timeCreated
timeLastEdited
}
}
variables {
id: ID,
info: See info example under "Shared data types"
}
This endpoint adds a person with a relation as client, to a specific case. You can set different information pieces on the client.
The system can deduce if a client already exists with the info you are adding. If so, any new information will be appended to the existing person client.
The definition for PersonInfo variables can be found under "Shared data types"
Get all persons
query {
persons(amount: amount) {
items {
item {
id
name
}
cursor
}
totalCount
pageInfo {
hasPreviousPage
beforeCursor
hasNextPage
afterCursor
}
}
}
variables {
amount: 10,
}
This query retrieves all persons.
This query is paginated. You can learn more about how this works in the Pagination section.
Get a person by ID
query {
person(id: ID) {
id
name
timeCreated
timeLastEdited
}
}
variables {
id: ID,
}
This query retrieves a specific person.
Variables
Variable | Description |
---|---|
ID | The ID of the person to retrieve |
Get chunks from a person
query getPersonDocuments($id: ID!) {
person(id: $id) {
documents {
id
payload
subType
payloadSize
mimeType
timeCreated
timeLastEdited
}
}
}
variables {
id: ID,
}
See the shared data types for an explanation of Chunks.
Persons have several types of chunks, they are listed below with their chunk type, and their graphql field. They have the exact same fields
Type and corresponding GraphQL field
Type | GraphQL |
---|---|
Document | documents |
ContactInfo_Email | |
PhoneNumber | ContactInfo_Phone |
IdentityValidationToken | IdentityValidationToken |
EconomicCustomerNumber | ExternalId_Vendor_Economic_CustomerNumber |
GenericCustomerNumber | ExternalId_GenericCustomerNumber |
DKCVRApiIds | ExternalId_DK_CVR_APIId |
DKCPRNumbers | ExternalId_DK_CPR_Number |
ListCheck | listChecks |
ListCheck | latestListCheck |
Variables
Variable | Description |
---|---|
ID | The ID of the person to retrieve chunks for |
Add a contact-person to a Case
mutation AddContactPersonToCase($id: ID!, $info: PersonInfo!) {
addContactPersonToCase(id: $id, info: $info) {
id
name
timeCreated
timeLastEdited
}
}
variables {
id: ID,
info: See info example under "Shared data types"
}
This mutation adds a contact-person with a relation as contact, to a specific case. You can set different information pieces on the person.
The system can deduce if a contact-person already exists with the info you are adding. If so, any new information will be appended to the existing contact-person.
Variables
Variable | Description |
---|---|
ID | The ID of the case to add the person to |
The definition for PersonInfo variables can be found under "Shared data types"
Get all contact-persons for a Case
query getContactPersons($id: ID!) {
case(id: $id) {
id
name
contactPersons {
id
name
}
timeCreated
timeLastEdited
}
}
variables {
id: ID,
}
This query retrieves a specific case's contact-persons.
Variables
Variable | Description |
---|---|
ID | The ID of the case to retrieve contact-persons for |
Client Mutations
Here you can see mutations that are shared for both the Person client type, and the Company client type.
Set preferred language on person or company
mutation setPreferredLanguageForCompanyOrPerson($id: ID!, $language: String!) {
setPreferredLanguageForCompanyOrPerson(id: $id, language: $language) {
id
name
timeCreated
timeLastEdited
}
}
variables {
id: ID!,
language: String!,
}
This mutation sets the preferred language on person or company.
It can currently set these languages:
- da
for Danish
- en
for English
- de
for German
- no
for Norwegian
Variables
Variable | Description |
---|---|
id | The id of the company or person to set the language for |
language | The language to set on the person or company, |
Contact-persons
Contact-persons are identical to persons, they only differ in their relation to the case and/or company.
Add a contact-person to a Case
mutation AddContactPersonToCase($id: ID!, $info: PersonInfo!) {
addContactPersonToCase(id: $id, info: $info) {
id
name
timeCreated
timeLastEdited
}
}
variables {
id: ID,
info: See info example under "Shared data types"
}
This mutation adds a contact-person with a relation as contact, to a specific case. You can set different information pieces on the person.
The system can deduce if a contact-person already exists with the info you are adding. If so, any new information will be appended to the existing contact-person.
Variables
Variable | Description |
---|---|
ID | The ID of the case to add the person to |
The definition for PersonInfo variables can be found under "Shared data types"
Get all contact-persons for a Case
query getContactPersons($id: ID!) {
case(id: $id) {
id
name
contactPersons {
id
name
}
timeCreated
timeLastEdited
}
}
variables {
id: ID,
}
This query retrieves a specific case's contact-persons.
Variables
Variable | Description |
---|---|
ID | The ID of the case to retrieve contact-persons for |
Contact-points
Contact-points are email or text messages sent to your clients. They include a link to Reach where documents and personal information can be entered securely.
Send ContactPoint Via Email
mutation sendContactPointEmail($contactInfoId: ID!, $caseId: ID!) {
sendContactPointEmail(contactInfoId: $contactInfoId, caseId: $caseId) {
token
url
type
timeCreated
timeLastEdited
}
}
variables {
contactInfoId: ID,
caseId: ID
}
This mutation sends a contactpoint to an email for a case. Not that you need the ID of the Case and the ContactInfo/Email
Chunk.
Variables
Variable | Description |
---|---|
contactInfoId | The ID of the ContactInfo/Email chunk |
caseId | The ID of the case to send the ContactPoint for |
The definition for Chunk type can be found under "Shared data types"
Send ContactPoint Via Phone
mutation sendContactPointPhone($contactInfoId: ID!, $caseId: ID!) {
sendContactPointPhone(contactInfoId: $contactInfoId, caseId: $caseId) {
token
url
type
timeCreated
timeLastEdited
}
}
variables {
contactInfoId: ID,
caseId: ID
}
This mutation sends a contactpoint to an email for a case. Not that you need the ID of the Case and the ContactInfo/Phone
Chunk.
Variables
Variable | Description |
---|---|
contactInfoId | The ID of the ContactInfo/Phone chunk |
caseId | The ID of the case to send the ContactPoint for |
The definition for Chunk type can be found under "Shared data types"
Create a contactpoint without sending it
mutation createReachLink($caseId: ID!) {
createReachLink(caseId: $caseId) {
token
url
type
timeCreated
timeLastEdited
}
}
variables {
caseId: ID
}
This mutation does not send any emails or phone messages, you get a link you can embed or provide to the client as you see fit.
Variables
Variable | Description |
---|---|
caseId | The ID of the case to create the ContactPoint for |
Pagination
The initial request looks like this. We only get 5 elements and are thus on the first page:
query getCases($amount: Int) {
cases(amount: $amount) {
items {
item {
id
name
}
cursor
}
totalCount
pageInfo {
hasPreviousPage
beforeCursor
hasNextPage
afterCursor
}
}
}
variables {
amount: 6
}
We get the elements with cursors, and page info:
{
"data": {
"cases": {
"items": [
{
"item": {},
"cursor": "1"
},
{
"item": {},
"cursor": "2"
},
{
"item": {},
"cursor": "3"
},
{
"item": {},
"cursor": "4"
},
{
"item": {},
"cursor": "5"
}
],
"totalCount": 123,
"pageInfo": {
"hasPreviousPage": false,
"beforeCursor": "1",
"hasNextPage": true,
"afterCursor": "5"
}
}
}
}
The Public API uses a cursor-based pagination system.
Each set of items, in this example cases, are wrapped in an items
field, and each case is defined as an item
in that items-field.
This means the case is the item.
You can supply an amount
variable, to limit the amount of items you get. It defaults to 100.
A cursor is returned for each item. This first and last cursor is also returned in the pageInfo
field.
To aid in pagination, you can retrieve a totalCount
and both a hasPreviousPage
and a hasNextPage
, indicating whether pagination in wither direction is possible.
You can move forwards and backwards in the results by supplying a cursor to either the after
or before
variables.
Variables
The second request wants the next page and sends in the
afterCursor
as theafter
variable:
query getCases($amount: Int, $after: String) {
cases(amount: $amount, after: $after) {
items {
item {
id
name
}
cursor
}
totalCount
pageInfo {
hasPreviousPage
beforeCursor
hasNextPage
afterCursor
}
}
}
variables {
amount: 5,
after: "5",
}
This results in the second page being returned:
{
"data": {
"cases": {
"items": [
{
"item": {},
"cursor": "6"
},
{
"item": {},
"cursor": "7"
},
{
"item": {},
"cursor": "8"
},
{
"item": {},
"cursor": "9"
},
{
"item": {},
"cursor": "10"
}
],
"totalCount": 123,
"pageInfo": {
"hasPreviousPage": true,
"beforeCursor": "6",
"hasNextPage": true,
"afterCursor": "10"
}
}
}
}
Name | type | Description |
---|---|---|
amount | Integer | The amount of items to return, defaults to 100 |
after | String | The after variable gets the amount of items after the supplied cursor. |
before | String | The before variable gets the amount of items before, or behind the supplied cursor. |
Errors
The Public API uses the following error codes:
Error Code | Meaning |
---|---|
400 | Bad Request -- Your request is invalid. |
401 | Unauthorized -- Your API key is wrong. |
403 | Forbidden -- The element requested is hidden for administrators only. |
404 | Not Found -- The specified element could not be found. |
405 | Method Not Allowed -- You tried to access a element with an invalid method. |
406 | Not Acceptable -- You requested a format that isn't json. |
410 | Gone -- The element requested has been removed from our servers. |
429 | Too Many Requests -- You're requesting too many elements! Slow down! |
500 | Internal Server Error -- We had a problem with our server. Try again later. |
503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |