Skip to content

Receive Verified Data

When a verification session completes, the verification service pushes the result to your application. This is step 6 of the verification flow, and configuring it is how you get the claims without polling.

Requirements

1. Expose an endpoint

Your application needs an endpoint that accepts POST requests with a JSON body. The verification service calls it once per completed session.

Give it a secret and check it. The configuration below sends a bearer token with every call; verify it on your side before processing the body. Without that check, the endpoint is an unauthenticated way into your application for anyone who learns the URL.

2. Configure the callback

Set sessionCallback in the verification service's server.json:

server.json (truncated)
{
  "port": "...",
  "baseUrl": "...",
  "database": {
    "..."
  },
  "signing": {
    "..."
  },
  "sessionCallback": { // (1)!
    "targetUrl": "https://example-application.com/verified-claims", // (2)!
    "bearerToken": "5I90CwXlZoolopOSplVBOoV63qXSTEo4piJKJ0iizFau79HU6viEvzgGReWycN8V" // (3)!
  }
}
  1. Where verification results are pushed, and how the request authenticates itself.
  2. Required within this block. The URL of the endpoint from step 1. It must be reachable from inside the verification service's container — not merely from your desktop.
  3. Optional, but configure it. Sent as Authorization: Bearer <value> on every callback.

claims and destinationUrl still work

This block used to be called claims, with the URL under destinationUrl. Both older names are still accepted as aliases, so an existing configuration keeps working. New configurations should use sessionCallback and targetUrl — the issuer uses the same names, so the two services stay consistent.

An auth field was described in older documentation. It does not exist. Authentication is bearerToken.

3. Restart the service

Configuration is read at startup. Stop the container and start it again with the updated file:

docker run -d \
  -p 8081:8081 \
  -w /app \
  -v "$(pwd)/verifier/conf:/app/conf:ro" \
  registry.gitlab.com/secata/platform/did/release/verifier-backend:latest

What you receive

curl -X POST 'https://example-application.com/verified-claims' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer 5I90CwXlZoolopOSplVBOoV63qXSTEo4piJKJ0iizFau79HU6viEvzgGReWycN8V' \
  -d '{
  "session_id": "14eb99d399dda3264a0ad85b93b26eab5396ce17e50056968c2749049ebf6ec1",
  "verification_result": true,
  "claims": {
    "first_name": "Jens",
    "last_name": "Jensen",
    "city": "Aarhus"
  }
}'
  • session_id matches what you got back when you started the session. Use it to tie the result to the right interaction.
  • verification_result is whether the presentation passed cryptographic validation.
  • claims holds the disclosed values.

How claim keys are named

The keys in the claims object are chosen in this order of priority:

  • The id field, if you specified one on the claim in the DCQL query.
  • Otherwise, the elements of path joined with dots — e.g. address.city.

Set id on every claim you query if you want key names that are stable against changes to the credential structure.

What verification_result: true covers

The presentation was correctly signed and untampered, and the issuer's certificate chain validated against the trust anchors you configured. With no anchors configured that last check does not run — see Trust model.

Accept or reject the result

The verification service checks that the presentation is genuine. Whether the claims are good enough for your application — the holder is old enough, the membership has not lapsed — is your decision, and you give it in the HTTP status your endpoint answers with:

Your endpoint Session status
Answers with a 2xx status VERIFICATION_SUCCEEDED
Answers with any other status DELIVERY_REJECTED
Cannot be reached, or does not answer in time DELIVERY_FAILED

The callback is sent once and is not retried, so answer with a 2xx only once you have taken the result in. The holder's wallet waits while your endpoint runs, so answer within a few seconds and do any slow work afterwards.

Answer with a JSON body that says why, especially when you reject:

{
    "message": "The holder must be at least 18 years old."
}

The verification service stores the body you answer with verbatim on the session, for audit, both when you accept and when you reject. Only the status decides the outcome: the body is not interpreted, so a missing or non-JSON body changes nothing. The body is not returned by the status endpoint. Keep personal data out of it — the claims you received do not belong in the answer.

Results that did not verify

A session that ends in VERIFICATION_FAILED or WALLET_REJECTED is also sent to your endpoint, with verification_result: false and no claims. There is nothing to accept, so your answer to that call is ignored and not stored.

If results do not arrive

Check, in order:

  1. targetUrl is reachable from inside the container — not just from your machine.
  2. Your endpoint returns a success status.
  3. The session actually completed: GET /presentation/oid4vp/status/{session_id} and read error_message.

More in Troubleshooting.

What's Next