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

# Age verification

> Require customers to prove they meet a minimum age before completing checkout, using BankID or MitID.

Age verification stops checkout until the customer has proven they are old enough. It applies to the whole session, not a single payment method. The customer authenticates with BankID or MitID.

This is currently only available for customers in Norway, Sweden, and Denmark.

In hosted checkout they are asked to verify before they can choose a payment method. If you drive checkout yourself, follow the `complete-age-verification` operation.

## How It Works

```mermaid theme={null}
sequenceDiagram
    participant Customer
    participant Dintero
    participant IdP

    Customer->>Dintero: Opens checkout
    Dintero->>IdP: Redirect to BankID / MitID
    IdP-->>Dintero: Identity + birthdate

    alt Age meets requirement
        Note over Dintero: AGE_VERIFICATION_COMPLETED
        Dintero-->>Customer: Checkout with payment methods
    else Too young, cancelled, or failed
        Dintero-->>Customer: Redirect with error
    end
```

1. Enable `age_verification` on the session (or session profile).
2. The customer opens checkout and verifies their age before they can pay.
3. They authenticate with BankID or MitID.
4. The session records `AGE_VERIFICATION_COMPLETED` with `verified_identity.age_over`.
5. Checkout continues as usual. The transaction copies that identity unless the payment type already has one.

## Step-by-Step Implementation

### 1. Configure the Session

Set `age_verification` on `POST /v1/sessions`:

```http theme={null}
POST /v1/sessions
Authorization: Bearer <token>
Content-Type: application/json

{
  "url": {
    "return_url": "https://example.com/accept",
    "callback_url": "https://example.com/callback"
  },
  "order": {
    "amount": 29900,
    "currency": "NOK",
    "vat_amount": 5980,
    "merchant_reference": "order-123",
    "items": [
      {
        "amount": 29900,
        "quantity": 1,
        "line_id": "1",
        "description": "Age-restricted item",
        "vat": 25,
        "id": "item-1"
      }
    ]
  },
  "configuration": {
    "age_verification": {
      "enabled": true,
      "minimum_age_required": 18
    }
  }
}
```

### 2. Customer Completes Verification

**Hosted checkout.** Nothing extra to build. Checkout asks the customer to verify their age before they can pick a payment method, then sends them to BankID or MitID and brings them back to the session.

<img src="https://mintcdn.com/dintero-c3a7bfec/XcvJgiNLXtm0IKyL/docs/assets/checkout/checkout_age_verification.png?fit=max&auto=format&n=XcvJgiNLXtm0IKyL&q=85&s=cc6bc786a4f7d977c4c7580ed146b2bf" alt="Age verification in checkout" width="1160" height="1298" data-path="docs/assets/checkout/checkout_age_verification.png" />

**Custom or API checkout.** If you start a payment while verification is still required, the response contains only this operation:

```json theme={null}
{
  "operations": [
    {
      "rel": "complete-age-verification",
      "method": "GET",
      "content_type": "text/html",
      "href": "https://checkout.dintero.com/v1/view/{session_id}/age-verification"
    }
  ]
}
```

Send the customer to `href`. After they pass, they come back with `sid`. Retry the payment. The operation is gone once `age_over` meets `minimum_age_required`.

<Info>
  Starting verification again reuses the pending identity-provider URL for a few minutes, so the customer is not sent through BankID or MitID twice.
</Info>

### 3. Receive the Session Event

A successful verification appends `AGE_VERIFICATION_COMPLETED`. The national identity number is never included.

```json theme={null}
{
  "name": "AGE_VERIFICATION_COMPLETED",
  "details": {
    "verified_identity": {
      "type": "dintero-idp",
      "age_over": 21,
      "acr": "nobankid-oidc",
      "national_country": "NO",
      "auth_time": "2026-09-02T10:00:00Z"
    }
  }
}
```

When the transaction is created, that `verified_identity` is copied onto it.

## Configuration Options

| Option                 | Type    | Required | Description                              |
| ---------------------- | ------- | -------- | ---------------------------------------- |
| `enabled`              | Boolean | Yes      | Turn age verification on for the session |
| `minimum_age_required` | Integer | Yes      | Minimum age, for example `18`            |

The identity provider country is taken from, in order:

1. `order.billing_address.country`
2. `order.shipping_address.country`
3. `configuration.countries.preferred_country`

| Country | Identity provider |
| ------- | ----------------- |
| `NO`    | BankID            |
| `SE`    | BankID            |
| `DK`    | MitID             |

If the country is missing or unsupported, the customer picks from the providers above.

## Verified Age

The exact age is not stored. `age_over` is the highest of `21`, `18`, `16`, and `15` that the customer meets, and that is still at least `minimum_age_required`.

| Actual age | `minimum_age_required` | `age_over`         |
| ---------- | ---------------------- | ------------------ |
| 30         | 18                     | 21                 |
| 19         | 18                     | 18                 |
| 17         | 18                     | Redirect, no event |

## Failures and Redirects

If verification fails or is cancelled, the customer is sent back to the session URL with `error` and `merchant_reference` (when available). Embed context (`ui`, `sdk`) is kept.

| `error`                   | Meaning                                                                          |
| ------------------------- | -------------------------------------------------------------------------------- |
| `age-requirement-not-met` | Authenticated, but too young. No `AGE_VERIFICATION_COMPLETED` event.             |
| `cancel`                  | The customer cancelled at the identity provider.                                 |
| `authorization-failed`    | Authorization with the identity provider failed.                                 |
| `failed`                  | Verification could not be completed, for example if age could not be determined. |

## Direct Pay

`POST /v1/sessions/{session_id}/pay` is blocked until verification completes:

```json theme={null}
{
  "success": false,
  "error": "age-verification-required",
  "redirect_url": "https://checkout.dintero.com/v1/view/{session_id}/age-verification",
  "actions": [
    {
      "source": "DINTERO",
      "code": "age-verification-required",
      "type": "error"
    }
  ]
}
```

Send the customer to `redirect_url`, then retry the pay request.

<Info>
  The customer has to complete verification themselves. Merchant-initiated or headless pay can still use age verification if you send the customer to `redirect_url` first, but it may not fit flows where no customer is present.
</Info>

## Identity Verification

If a payment type on the session also needs identity verification, age verification collects that identity at the same time. The customer is not asked to authenticate twice.

The national identity number is never exposed on the session event or on the transaction in API responses.

If the payment type later verifies identity itself, that identity is kept on the transaction.

## See Also

* [Create a session](/docs/checkout/create-session): enable `age_verification` when you create the session
* [Show checkout](/docs/checkout/display-checkout): hosted checkout handles the redirect for you
* [Handling payment](/docs/checkout/after-payment): the transaction after checkout completes
