> ## 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.

# Verification Flow

> The statuses a verification moves through, and the five flow types that decide what the user does.

## Lifecycle

A verification is created against one [connection](/v2/guides/concepts/connections) and ends in one of four terminal statuses. It expires at `expiresAt`, **30 minutes** after creation, if it has not finished.

```mermaid theme={null}
stateDiagram-v2
    direction LR
    [*] --> awaiting_user_action: create
    awaiting_user_action --> authenticating: user acts (some providers)
    awaiting_user_action --> completed
    authenticating --> completed
    awaiting_user_action --> failed
    authenticating --> failed
    awaiting_user_action --> cancelled
    authenticating --> cancelled
    awaiting_user_action --> expired: expiresAt
    authenticating --> expired: expiresAt
```

| Status | Meaning |
| :- | :- |
| `awaiting_user_action` | Waiting for the user. Returned by create, except for `query` connections. |
| `authenticating` | The user started at the provider. Not every provider reports it. |
| `completed` | Done. Read the result from userinfo. |
| `failed` | Ended in failure. `error.code` says why. |
| `cancelled` | You or the user cancelled. |
| `expired` | Not finished by `expiresAt`. Start a new verification. See below. |

<Note>
  `processing` appears in the schema but is never returned. If you see it, treat it like `authenticating`.
</Note>

A verification belongs to the app that created it. Read and cancel it with the same app's credentials. Any other app gets `404`.

### Expiry

`expired` names an outcome. The API does not return it. Expiry is decided by time alone: a verification that has not finished by its `expiresAt` has expired.

Every verification, finished or not, is kept only until `expiresAt`. After that, every call for it returns `404`. So read `expiresAt` from the create response, stop waiting when it passes, and read userinfo as soon as the status is `completed`.

The Console's **Security & Compliance → Audit Log** keeps the record and shows it as `expired`. No webhook is sent for expiry.

## Flow types

The connection decides the flow type. With [OIDC](/v2/guides/oidc-integration), Hopae handles every flow for you. With the [REST API](/v2/guides/api-integration), your app does the user-facing part.

| Flow type | What the user does | Your app (REST) | Examples |
| :- | :- | :- | :- |
| `redirect` | Signs in on the provider's page | Send the user to `authorizationUrl` | `mitid`, `id-austria` |
| `qr` | Scans a QR code with an eID app | Show `qrData`, then poll | `freja-plus`, `diia` |
| `push` | Approves on a registered phone | Show `verificationCode`, then poll | `smart-id`, `sk-mobile-id` |
| `dc` | Shares a credential from a phone wallet | Open `linkData` on the phone, then poll | `google-wallet-us-mdl` |
| `query` | Nothing. Hopae checks the data you sent with the source | Read the create response. It is already final | `ng-nin`, `br-cpf` |

<Card title="Flow types in detail" icon="route" href="/v2/guides/reference/flow-types">
  Sequence diagrams, full responses, and same-device handling for each flow type.
</Card>

## The hosted flow

With OIDC, the user picks **country → credential → provider** on a Hopae-hosted page. Only connections enabled in the [workflow](/v2/guides/verifications/workflows) are offered. The provider step appears only when a credential is available through more than one provider. To skip the picker, pass `ui_connection_id`. See [OIDC Integration](/v2/guides/oidc-integration#pre-select-a-connection).


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