Datakeeper API Verifier
Overview
To request verified data from an end-user, you can create a session for them. A session is a temporary instance that holds the state of the verification process. The session can be monitored and managed through various API endpoints. A common flow will consist of the following steps:
- First-time setup: use the
/organizations/myendpoint to check your access to the tenant and retrieve the delegated tenant ID - Create a session starting with a POST request to
/sessions - Get a QR-code to share with the end-user by sending a GET request to
/sessions/{sessionId}/qr - The end-user scans the QR-code with their wallet app and completes the verification transaction, this triggers the webhook callback set on session creation
- Get the results by sending a GET request to
/verification-status/{transactionId}. Although using a webhook is recommended, it's also possible to poll this endpoint until the transaction is completed - After processing the transaction data, you have to delete the transaction and the corresponding session by sending a DELETE request to
/transaction-status/{transactionId}
It's important the transaction is immediately removed after processing the data by calling the DELETE-endpoint, so we don't hold on to unnecessary personal data. If the transaction is not deleted after completion, it will be automatically deleted after some period as a safety measure.
Getting your delegated tenant ID
There is a multi-tenant architecture where multiple organizations can use the same Digital Identity Service Provider to do data verifications. Each tenant represents an organization, and you are required to specify on whose behalf you are requesting the data.
You can retrieve your delegated tenant ID by sending a GET request:
GET /organisations/my With the delegated tenant ID in the response, you can proceed to create sessions and request data on behalf of that tenant. The identifier will not change, so you can safely store it in your system after the first retrieval. The response will also contain the status of your access to the main tenant, which should be APPROVED in order to successfully create sessions. Here's an example response:
{
"delegatedTenantId": "de2f912b-3bdd-4893-9614-2f93b04b934c",
"status": "APPROVED"
}Creating a verification session
Here's an example request to create a verification session requesting a phone number and an email address:
POST /sessions
Content-Type: application/json
{
"toAttest": {},
"toVerify": [
{
"@context": [
"https://schema.org/government-documents#phone-number"
],
"predicate": "phoneNumber",
"correlationGroup": "1",
"allowedIssuers": [
"did:eth:0x159F556B01A9Ceaa5008Bfb3286752C7e83B70bf"
]
},
{
"@context": [
"https://schema.org/government-documents#email"
],
"predicate": "email",
"correlationGroup": "2",
"allowedIssuers": [
"did:eth:0x159F556B01A9Ceaa5008Bfb3286752C7e83B70bf"
]
}
],
"purpose": "Some GDPR-compliant purpose for requesting the data",
"delegatedTenant": "de2f912b-3bdd-4893-9614-2f93b04b934c",
"userId": "user-12345",
"webhook": {
"version": "1",
"endpoint": "https://mycompany.com/api/webhook-callback"
}
}The toVerify field in the request body of the session creation endpoint is used to specify what data you want to request from the end-user. This field is an array of objects, where each object represents a request for a specific data point. There are a few important concepts to understand for toVerify objects:
- The
@contextfield contains an array of schemas that correspond to the documents that can provide the requested data. Some data can be found in multiple documents, so you can specify multiple contexts. The user will be able to choose from which document they want to share the data. - The
predicatefield is used to specify the exact data point you want to request. Each predicate corresponds to a specific top-level field in the document schema. This allows for data minimization, as you request only the data you need. - The
allowedIssuersfield is an array of Decentralized Identifiers (DIDs) that represent the trusted issuers of the documents. By specifying allowed issuers, you ensure that the data comes from a reliable source. For production environments, it is recommended to use Datakeeper's production identifier as the sole allowed issuer. - The
correlationGroupfield is used to group related data points that should come from the same document. This is useful when you need multiple pieces of information that are logically connected, such as a person's name and date of birth. By assigning the same correlation group to these predicates, you ensure that they are sourced from the same document. It is important to use a different correlation group for each document (specified in the@contextfield).
On the top level of the request body, you also have to specify the purpose field, which is a human-readable explanation of why you are requesting the data. This is mandatory as it explains to the end-user why they share their personal information with you.
The delegatedTenant field is used to specify the tenant on whose behalf you are requesting the data. This is required in multi-tenant scenarios, such as here where the Digital Identity Service Provider (like Rabobank BaaS) assists multiple organizations in doing data verifications. You should use the tenant ID that is provided in the /organizations/my endpoint.
Finally, in order to link the verification session to a specific user in your system, you can use the userId field. This field will be returned in the response of the verification status endpoint, allowing you to associate the verified data with the correct user.
To reiterate, it is possible to ask for multiple data points from different documents in a single session. Within the same correlation group, all requested data points must be present in the same document. It is not possible to mix data points from different documents within the same correlation group. Also make sure @context and allowedIssuers are always identical within the same correlation group.
Allowed issuer identifiers
In the sandbox environment it's common to issue data yourself in order to test the full flow. For this reason, it makes the most sense to use the sandbox identifier of the Rabobank Embedded Services solution as allowed issuer for your data requests.
For production environments, you are required to use the Datakeeper production identifier as the allowed issuer. This is the trusted issuer in our production environment for data that Datakeeper provides to the end-users in the wallet.
Use the following identifiers in the allowedIssuers field when creating a session, depending on the environment you are working in:
| DID-identifier | Description |
|---|---|
did:eth:0x159F556B01A9Ceaa5008Bfb3286752C7e83B70bf | Datakeeper Production |
did:eth:0xe6ABd750D5c134f881104D446A00e727D9Fa4413 | Datakeeper Rabobank Sandbox |
Webhook callback
When creating a session, you can specify a webhook URL that will be called when the end-user completes the verification process. This allows you to receive real-time updates about the status of the verification without having to poll our verification-status endpoint.
Datakeeper will send a POST request to the specified webhook URL with a JSON body that looks like this:
{
"version": "1",
"event": "SESSION_STATUS_UPDATE",
"eventData": {
"userId": "user-12345",
"trxId": "trx-d8320032-a19e-4b97-ab37-a0d37335008b"
}
}The event type SESSION_STATUS_UPDATE indicates that the session has been updated. This is currently the only event type we send. The eventData object contains the userId you specified when creating the session and the trxId, which is the unique identifier for the verification transaction.
We only support webhook URLs that use HTTPS (port 443). TLS 1.2 or higher is required.
Retrieving verification results
After the end-user has completed the verification process, you can retrieve the results by sending a GET request to the /verification-status/{transactionId} endpoint. The transactionId is the trxId you received in the webhook callback.
Here's an example request to retrieve the verification results:
GET /verification-status/trx-d8320032-a19e-4b97-ab37-a0d37335008bThe response will contain the verified data in a structured format. Here's a part of an example response:
[
{
"id": "vtrxi-d405da7a-183f-4acc-a8ad-fe25c2771624",
"transactionId": "trx-d8320032-a19e-4b97-ab37-a0d37335008b",
"details": {
"did": "did:eth:0x32C6D59B83720BA50cdcf26642fBB85db2deecBD",
"issuer": "did:eth:0x159F556B01A9Ceaa5008Bfb3286752C7e83B70bf",
"predicateValues": {
"phoneNumber": "+31612345678"
}
},
"allowedIssuers": [
"did:eth:0x159F556B01A9Ceaa5008Bfb3286752C7e83B70bf"
],
"context": [
"https://schema.org/government-documents#phone-number"
],
"predicate": "phoneNumber",
"status": "CONFIRMED",
"createdAt": "2025-01-01T00:00:00.000Z",
"lastModifiedAt": "2025-01-01T00:00:00.000Z",
"sensitiveSince": "2025-01-01T00:00:00.000Z",
"correlationGroup": "1",
"isRetrieved": true,
"retrievalStatus": "RETRIEVED",
"expiresAt": 1738281600
},
...
]Issuing test data in the sandbox environment
In order to test the full flow of a data request session on the sandbox environment, you can issue test data yourself under the DID-identifier of the Rabobank Sandbox. This allows you to provide specific test data in order to complete a data request.
You can create a session with toAttest set with the data you want to issue, and then create and scan the QR-code with the Datakeeper app. In the app, you can choose to share the data you issued when creating a verification data request.
POST Create Session
https://api-sandbox.rabobank.nl/openapi/sandbox/datakeeper/sessions
Request
POST /sessions
Content-Type: application/json
{
"toAttest": {
"https://schema.org/government-documents#email": {
"predicates": {
"email": "[email protected]"
}
},
"https://schema.org/government-documents#phone-number": {
"predicates": {
"phoneNumber": "+31612345678"
}
}
},
"toVerify": [],
"delegatedTenant": "55586e05-b64e-4e9a-8a63-c9df35fc0aca",
"userId": "x"
}Response
{
"sessionId": "ses-83ee5e4a-2f99-4d08-9ec3-9332df71e180",
"qrcode": "https://ssi-api.dk.sandbox.cloud.datakeeper.nl/challenges/ses-83ee5e4a-2f99-4d08-9ec3-9332df71e180",
"transactionId": "trx-e3d5f562-01b9-4ba3-bf70-44c39d92a45c",
"dynamicLink": "https://datakeeper.app.link/?challenge_request=https%3A%2F%2Fssi-api.dk.sandbox.cloud.datakeeper.nl%2Fchallenges%2Fses-83ee5e4a-2f99-4d08-9ec3-9332df71e180"
}Get QR-code for session
https://api-sandbox.rabobank.nl/openapi/sandbox/datakeeper/sessions/{sessionId}/qr
Request
You can use the
sessionIdpresent in the response of your 'POST create session' request.
Response
data: image/png;base64,
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 when you add the header: Accept: image/png
GET verification transaction details
https://api-sandbox.rabobank.nl/openapi/sandbox/datakeeper/verification-status/{transactionId}
Request
You can use the
transactionIdpresent in the response of your 'POST create session' request.
Response
[
{
"id": "vtrxi-020fbc0c-9540-4370-88e9-a73d875b561c",
"transactionId": "trx-e3d5f562-01b9-4ba3-bf70-44c39d92a45c",
"details": {},
"allowedIssuers": [
"did:eth:0x159F556B01A9Ceaa5008Bfb3286752C7e83B70bf"
],
"context": [
"https://schema.org/government-documents#phone-number"
],
"predicate": "phoneNumber",
"status": "CREATED",
"createdAt": "2026-06-23T11:04:04.198Z",
"lastModifiedAt": "2026-06-23T11:04:04.198Z",
"correlationGroup": "1",
"retrievalStatus": "PENDING",
"expiresAt": 1784806849
},
{
"id": "vtrxi-58e72df4-d3fe-4a5f-bcad-1e31cfc2331e",
"transactionId": "trx-e3d5f562-01b9-4ba3-bf70-44c39d92a45c",
"details": {},
"allowedIssuers": [
"did:eth:0x159F556B01A9Ceaa5008Bfb3286752C7e83B70bf"
],
"context": [
"https://schema.org/government-documents#email"
],
"predicate": "email",
"status": "CREATED",
"createdAt": "2026-06-23T11:04:04.219Z",
"lastModifiedAt": "2026-06-23T11:04:04.219Z",
"correlationGroup": "2",
"retrievalStatus": "PENDING",
"expiresAt": 1784806849
}
]