> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hopae.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Return Data Model

> What we return after User Verification

Both integrations end at the same payload.

```mermaid theme={null}
flowchart LR
  O["OIDC: POST /token"] --> OU["GET /userinfo"]
  R["REST: GET /verifications/{id} until completed"] --> RU["GET /verifications/{id}/userinfo"]
  OU --> P["Same payload: user, match, and on request provenance and missing_claims"]
  RU --> P
```

## Overview

* Who is the user? → returned under `user`.
* Which connection verified them? → `provenance._metadata.provider_id`, `connection_id`, `credential_id`, and `connection_instance_id` within the same metadata block.
* How was this identity verified? → described by `provenance`.
* Did the user's claimed values match the source? → returned under `match` for match connections.

This data model is served by OIDC `/userinfo` (subject to granted scopes and the OIDC claim whitelist) and by the REST [Get Verification UserInfo](/v2/api-reference/verifications/get-verification-userinfo) endpoint. On both, `provenance` and `missing_claims` are returned only when the request asks for them with `provenance=true` and `missing_claims=true`.

## Connection identity

Under `provenance._metadata`, every userinfo result requested with `provenance=true` names the [connection](/v2/guides/concepts/connections) that ran, using the same ids you see in the Console and in [Get Connections](/v2/api-reference/verifications/get-connections):

| Field | Example | Meaning |
| :- | :- | :- |
| `provider_id` | `smart-id`, `google-wallet` | The provider that presented the credential. |
| `credential_id` | `smart-id`, `us-mdl` | The credential that was verified. |
| `connection_id` | `smart-id`, `google-wallet-us-mdl` | The catalog connection. Human-readable but opaque: read `provider_id` and `credential_id` instead of parsing it. |
| `connection_instance_id` | `conn_01J8XK2P4M9QR3TV` | Your app's activated instance of that connection, the id you started the verification with. |

There is no `amr` claim in v2. The ID token carries `provider_id` and `connection_id` inside one `hopae_verification` claim. `credential_id` and `connection_instance_id` are only in the userinfo response's `provenance._metadata`. All four identifiers are nested there in userinfo, never top-level.

## Verification models

The top-level `verification_model` field tells you which payload shape to read:

| `verification_model` | When | Read from | `user` |
| - | - | - | - |
| `disclosure` | The provider returned user attributes from an authoritative source. Default for classic providers and wallets. | `user.*` (PII) and `provenance` | object with PII |
| `match` | The provider compared the values you submitted against the authoritative source and returned a match outcome. | `match.*` and `provenance` | verified subset of the submitted fields |

`verification_model` is always present and is decided by the connection you verify against.

For match flows, `user` echoes back the verified subset of the values you submitted. Per-field providers: only fields with `matched: true`. Aggregate providers: every submitted field when the aggregate outcome is `true`, otherwise empty. A match connection may additionally expose disclosed (provider-asserted) claims. Those appear under `user` only when the workflow requests them, and a requested-but-unavailable claim is listed in `missing_claims`.

For match connections, the values to compare are supplied at session creation in `userInput`. The keys are **OIDC-normalized** names (see [Normalized User Data](/v2/guides/verifications/normalized-user-data)) and appear back in `match.submitted_fields` and as `match.details` keys. See [User Input](/v2/api-reference/verifications/user-input).

## Which claims you receive

The claims under `user` are the ones the [workflow](/v2/guides/verifications/workflows) requested: the claims on its **Claims** tab, plus any claims set for the connection that ran. Nothing in the request body changes this set.

`source_id`, a stable identifier for the same person on the same connection, is **opt-in** in v2. Tick **Source ID** on the workflow's **Claims** tab to receive it. When the connection cannot derive it for this person, `source_id` is listed in `missing_claims`. `sub` is **not** a stable user identifier: it is the verification id and changes on every verification.

## What "Provenance" means

Provenance is the audit trail of the verification: what the source actually returned, and when.

* Presentation
  * Credentials\[]: one entry per credential the source presented, carrying the source's own `claims` exactly as received (for match connections too) and, when the provider issues it, `evidence`.
  * Evidence (when present)
    * The original signed proof from the source (or a Hopae-signed equivalent when the provider issues none), so you can independently verify the result wasn't altered in transit. Shape and keys vary by provider. See [Evidence & Data Integrity](/v2/guides/verifications/evidence).
* Metadata
  * Catalog identity, verification identifiers, and timestamps for audit and support (`verification_id`, `verified_at`, `status`, and `error` when the session ended with an error).

Read `provenance._metadata` for the catalog provider, credential, connection, and activated instance IDs. These are snapshotted when the session starts. Resolve issuer details through the catalog and source evidence.

### UserInfo payload structure

Here is a conceptual map of the payload. For detailed field specifications, refer to the [Data Types](/v2/guides/data-types/user) pages.

```jsonc theme={null}
{
  "user": { "name": "Test User", "birthdate": "1990-01-01" },
  "missing_claims": ["email"],
  "acr": "urn:hopae:loa:4", // when reported by the provider
  "hopae_loa": 4,
  "hopae_loa_label": "high",
  "verification_model": "disclosure",
  "provenance": {
    "presentation": {
      "credentials": [
        {
          "claims": { "givenName": "Test", "surname": "User" }
          // evidence is optional and provider-specific
        }
      ]
    },
    "_metadata": {
      "verification_id": "019bc4f2-8a31-7c5e-9d02-4f7a1b3e60d8",
      "verified_at": "2026-09-21T09:19:52.110Z",
      "status": "completed",
      "provider_id": "smart-id",
      "connection_id": "smart-id",
      "credential_id": "smart-id",
      "connection_instance_id": "conn_01J8XK2P4M9QR3TV"
    }
  },
  "sub": "019bc4f2-8a31-7c5e-9d02-4f7a1b3e60d8"
}
```

### Match payload example

A complete userinfo response from a match connection (`id-nik-match`, Indonesia NIK):

```json theme={null}
{
  "user": {
    "name": "Test User",
    "birthdate": "1990-01-01"
  },
  "missing_claims": [],
  "hopae_loa": 4,
  "hopae_loa_label": "high",
  "verification_model": "match",
  "match": {
    "matched": true,
    "granularity": "per_field",
    "submitted_fields": [
      "name",
      "birthdate"
    ],
    "details": {
      "name": {
        "matched": true,
        "submitted_value": "Test User"
      },
      "birthdate": {
        "matched": true,
        "submitted_value": "1990-01-01"
      }
    }
  },
  "provenance": {
    "presentation": {
      "credentials": [
        {
          "claims": {
            "fullName": true,
            "dateOfBirth": true,
            "nationalIdNo": true
          },
          "evidence": {
            "token": {
              "integrator_jws": "eyJhbGciOiJSUzI1NiIsInR5cCI6...",
              "token_type": "integrator"
            },
            "names": "integrator_jws;token_type"
          }
        }
      ]
    },
    "_metadata": {
      "verification_id": "019bc4f7-2b44-7f1a-9c3d-8e5b0a6f2c77",
      "verified_at": "2026-09-03T10:02:19.551Z",
      "status": "completed",
      "provider_id": "id-nik",
      "connection_id": "id-nik-match",
      "credential_id": "id-nik-match",
      "connection_instance_id": "conn_01J8XQ4M2T7VBK8R"
    }
  },
  "sub": "019bc4f7-2b44-7f1a-9c3d-8e5b0a6f2c77"
}
```

<Note>
  For match connections, `provenance.presentation.credentials[].claims` carries the source's own response. This is the audit trail for what the source agreed with. It is not a duplicate of `match.details`. Note the intentional naming asymmetry: `userInput`, `match.submitted_fields`, and `match.details` use OIDC-normalized keys (e.g. `name`, `birthdate`), while `provenance` claims keep the source's native keys (e.g. `fullName`, `dateOfBirth`) so the audit trail stays aligned with the source.
</Note>

<Note>
  `details` may include keys that are not in `submitted_fields` when the upstream provider emits additional verifier results (e.g., a liveness signal alongside the demographic match outcome).
</Note>

## Related

* [Data Types: User](/v2/guides/data-types/user)
* [Data Types: Provenance](/v2/guides/data-types/provenance)
* [Level Of Assurance (LoA)](/v2/guides/verifications/assurance)
* [OIDC UserInfo](/v2/api-reference/oidc/userinfo)
* [REST UserInfo](/v2/api-reference/verifications/get-verification-userinfo)

## Next Steps

<CardGroup cols={2}>
  <Card title="OIDC Provider" icon="id-card" href="/v2/guides/oidc-integration">
    How OIDC fits into User Verification
  </Card>

  <Card title="Verification Flow" icon="diagram-project" href="/v2/guides/verifications/verification-flow">
    Understand the end-to-end lifecycle
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.