Age API quickstart

Nexiel Age proves “over 18,” not who someone is. It is a dedicated API surface, pricing, and documentation product for age-restricted online services (video-sharing platforms, social apps, e-commerce, gaming), built on top of Nexiel Verify's existing EUDI wallet / OpenID4VP stack: specifically the age-verification DCQL check type that already exists in that stack today.

New to EUDI wallets? Read what an EU Digital Identity Wallet is, and how a session works before this page assumes you already know what a DCQL query or an SD-JWT VC presentation is.

What this is, and what this isn't

This is not a separate identity-verification engine. Every request below hits the same Verify API service and the same POST /v1/verify/sessionsroute that Nexiel Verify's own docs describe, using the same underlying matching and storage. The only thing that changes is the request body's checkType, which determines which DCQL claims get requested. If you have already integrated Nexiel Verify for AML identity checks, the same credentials and integration pattern work for Nexiel Age: only the checkType value differs.

Scope, today: the only Nexiel Age capability live right now is the EUDI wallet age-verificationcheck type shown below. “Government-backed age assurance” beyond the EUDI wallet path is on the roadmap. Authentication uses the same API key as Nexiel Verify: there's no separate Age-only key yet. Pricing is published. See Nexiel Age's pay-as-you-go reference price on the pricing page.

Selective disclosure, made concrete

The age-verification DCQL template offers TWO alternative ways to answer the same age-over-18 question, via DCQL credential_sets: the EU's official Proof of Age / Age Verification (AV) attestation, a real EU-Commission-maintained credential with a native age_over_18boolean claim disclosed as-is, or the EUDI PID's birthdate claim, used only to compute that same boolean server-side and discarded immediately. A wallet answers exactly one of the two. The AV path is preferred wherever a wallet already holds it: it discloses a single, already-minimized boolean instead of a full birthdate, so it is strictly more data-minimizing than the PID fallback. The PID fallback exists because AV attestation issuance is still new and not yet universally held, and because the real PID Rulebook has no age_over_18claim, or any other age-derived claim, for a wallet to disclose directly — which is exactly why Nexiel Age never persists, logs, or returns the raw birthdate it computes from in that case. Neither alternative ever requests given_name, family_name, or nationalities. Those are what the separate aml-identitycheck type requests instead, for Nexiel Verify's and Nexiel Screen's identity-linked AML flow. The template itself is explicit about why:

The age-verification DCQL template
{
  "id": "age-verification",
  "version": 2,
  "description": "Age-gate check. Offers TWO alternative ways to satisfy the same age-over-18 question, via DCQL credential_sets: the EU's official Proof of Age / Age Verification (AV) attestation (a native age_over_18 boolean claim, disclosed as-is, the preferred path where the wallet holds it), or the PID's birthdate claim (used only to compute age_over_18 server-side, then discarded immediately -- never persisted or logged). Exactly one of the two is ever answered by a conformant wallet.",
  "dcqlQuery": {
    "credentials": [
      {
        "id": "av_age_over_18",
        "format": "mso_mdoc",
        "meta": {
          "doctype_value": "eu.europa.ec.av.1"
        },
        "claims": [
          {
            "path": [
              "eu.europa.ec.av.1",
              "age_over_18"
            ]
          }
        ]
      },
      {
        "id": "pid_birthdate",
        "format": "dc+sd-jwt",
        "meta": {
          "vct_values": [
            "urn:eudi:pid:1"
          ]
        },
        "claims": [
          {
            "path": [
              "birthdate"
            ]
          }
        ]
      }
    ],
    "credential_sets": [
      {
        "options": [
          [
            "av_age_over_18"
          ],
          [
            "pid_birthdate"
          ]
        ],
        "required": true
      }
    ]
  }
}

eu.europa.ec.av.1is the EU AV attestation's real ISO 18013-5 mdoc doctype, confirmed against the EU's own published AV trust list. urn:eudi:pid:1 and the birthdateclaim path are confirmed against the real PID Rulebook (v1.7) and the EU reference PID issuer's own served credential configuration. Neither is a placeholder value.

Nexiel Age runs on Nexiel Verify, which is live in production: compliance.nexiel.io serves /v1/verify/* today and always runs in production mode, so a real request there needs the bearer token described in the Verify API quickstart's Authentication section. Production completion of an age-verification check still fails closed for both alternatives today, for two independent reasons: the PID fallback depends on the EU's own eIDAS infrastructure publishing PID-Provider trust anchors, which has not happened yet; the AV path has a genuinely different, already-real trust list, but completing it in production also depends on this specific deployment having a current AV trust anchor snapshot configured, which it does not yet either. The requests and responses below are real, executed against a self-run instance with no VERIFY_API_MODE set, so you can see the exact shape you will integrate against without a wallet or an access token.

Sandbox mode

Same service as Nexiel Verify. Sandbox mode needs no signup or API key: run the service locally with no VERIFY_API_MODE set and every request below works exactly as shown, no seed step required.

The session-initiate step below is a plain HTTP request you can call directly. Completing a session requires a wallet-signed presentation, which a bare HTTP client can't produce on its own. The response shown is the exact shape your server receives once a wallet completes that step.

Create an age-verification session

curl -s -X POST https://compliance.nexiel.io/v1/verify/sessions \
  -H "Content-Type: application/json" \
  -d '{"clientId": "docs-example-client", "checkType": "age-verification"}'
200
{
  "sessionId": "8ab6d857-2cde-4108-a6f3-3f53a69e2fd7",
  "templateVersion": "age-verification@2",
  "authorizationRequest": {
    "client_id": "https://verify.nexiel.eu",
    "response_type": "vp_token",
    "response_mode": "direct_post",
    "response_uri": "https://compliance.nexiel.io/v1/verify/sessions/8ab6d857-2cde-4108-a6f3-3f53a69e2fd7/responses",
    "dcql_query": {
      "credentials": [
        {
          "id": "av_age_over_18",
          "format": "mso_mdoc",
          "meta": {
            "doctype_value": "eu.europa.ec.av.1"
          },
          "claims": [
            {
              "path": [
                "eu.europa.ec.av.1",
                "age_over_18"
              ]
            }
          ]
        },
        {
          "id": "pid_birthdate",
          "format": "dc+sd-jwt",
          "meta": {
            "vct_values": [
              "urn:eudi:pid:1"
            ]
          },
          "claims": [
            {
              "path": [
                "birthdate"
              ]
            }
          ]
        }
      ],
      "credential_sets": [
        {
          "options": [
            [
              "av_age_over_18"
            ],
            [
              "pid_birthdate"
            ]
          ],
          "required": true
        }
      ]
    },
    "nonce": "amIcbtsnz9umxzWKu--gPBHPUUmcH5R4TukgGSw-ALI",
    "state": "jqz4jEBGULUkWgkp_lcpBsbgbV3adNuJvx5xxk55gus"
  },
  "authorizationRequestUri": "openid4vp://authorize?client_id=https%3A%2F%2Fverify.nexiel.eu&response_type=vp_token&...(truncated)",
  "expiresAt": "2026-07-05T17:27:16.353Z"
}

Notice the dcql_query names two alternative credentials, joined by credential_sets, not one. A platform integrating Nexiel Age never receives a birthdate, or any other identity claim, either way: the AV alternative discloses only an already-native boolean, and the PID alternative's birthdate is computed into a boolean and the raw value discarded before this API ever sends a response back to your server.

The wallet discloses a birthdate; you get back a boolean

The end user's wallet resolves authorizationRequestUriand answers with exactly one of the two alternatives above: the AV attestation's native age_over_18 boolean, disclosed as-is, or the PID's birthdate claim, POSTed back to response_uri and computed into age_over_18immediately, then discarded. Either way this API returns the same boolean shape. A wallet whose disclosed birthdate shows the holder is 18 or older, or whose AV attestation's native claim is already true, produces:

POST /v1/verify/sessions/{sessionId}/responses
{
  "sessionId": "8ab6d857-2cde-4108-a6f3-3f53a69e2fd7",
  "method": "eudi_wallet",
  "booleanProofs": {
    "ageOver18": true
  },
  "amlResult": null,
  "pepFlag": null,
  "sanctionedFlag": null,
  "listsChecked": [],
  "humanReviewRequired": false,
  "templateVersion": "age-verification@2",
  "frozenDecisionArtifact": null
}

amlResult, pepFlag, sanctionedFlag, and listsChecked are all null/empty by construction: an age-verification check never runs the sanctions/PEP matching engine at all, so there is nothing to screen and nothing to human-review. frozenDecisionArtifact is nullfor the same reason: Nexiel's frozen-decision-artifact discipline (engine version, list snapshot, ensemble weights hash, gates hash) exists to make a screening decision re-derivable months later. An age check that never screened anyone has no decision to freeze.

What gets persisted

Same data-handling discipline as every Nexiel Verify flow, applied to the narrowest possible claim set: a platform integrating Nexiel Age gets a boolean to act on, never a birthdate to store and eventually leak.

Reference

Nexiel Age has no separate API reference. Every route, parameter, and response schema it uses is documented on the Verify API reference. The two routes this page walks through are POST /v1/verify/sessions and POST /v1/verify/sessions/{sessionId}/responses with checkType: "age-verification".

Roadmap