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

# Retrieve a widget session result

Retrieve the complete verification result for a specific eKYC widget session, including verification checks, government-issued identity data, biometric scores, and session timestamps.

### GET Endpoint

```json theme={null}
GET https://api.lumiid.com/api/v1/widgets/sessions/{session_id}/result/
```

### Authentication

Authentication is performed using your LumiID API key in the `Authorization` header.

```javascript theme={null}
Authorization: Bearer YOUR_SECRET_API_KEY
Accept: application/json
```

Keep your API key secure and make requests from your backend.

### Path parameters

| Parameter | Type | Required | Description |
| :- | :- | :- | :- |
| `session_id` | UUID | Yes | Unique ID of the widget verification session. |

### Example request

cURL

```php theme={null}
curl -X GET \
  "https://api.lumiid.com/api/v1/widgets/sessions/f23bd55e-fbe5-4e48-a374-ee7203d240e0/result/" \
  -H "X-API-Key: YOUR_LUMIID_API_KEY" \
  -H "Accept: application/json"
```

## Successful response

HTTP status: `200 OK`

The endpoint returns the session metadata, verification results, identity information and webhook delivery status.

```json theme={null}
{
  "session_id": "f23bd55e-fbe5-4e48-a374-ee7203d240e0",
  "widget_id": "068aa230-fdaf-4460-8ed8-e2c40e829db7",
  "status": "success",
  "selected_country": "NG",
  "selected_id_type": "bvn",
  "confidence_score": 0.93,
  "liveness_score": 0.95,
  "checks": {
    "face": true,
    "liveness": true,
    "spoof": "PASSED",
    "match": true,
    "match_band": "MATCH",
    "device_risk": {
      "suspicious_label": false,
      "resolution_mismatch": false
    },
    "timing_risk": {
      "evaluated": false
    }
  },
  "gov_data": {
    "bvn": "***********",
    "firstname": "Samson",
    "lastname": "Jabo",
    "middlename": "",
    "birthdate": "07-07-1995",
    "gender": "Male",
    "phone": "08000000001",
    "photo": "BASE64_ENCODED_IMAGE"
  },
  "webhook_delivered": true,
  "created_at": "2026-08-20T12:05:32.859909+00:00",
  "completed_at": "2026-08-20T12:09:00.466921+00:00"
}
```

The BVN and photo have been masked or abbreviated in this example for security and readability. The actual response returns the fields provided by the verification session.

## Response fields

### 1. Session information

| Field | Type | Description |
| :- | :- | :- |
| `session_id` | string (UUID) | Unique verification session identifier. |
| `widget_id` | string (UUID) | ID of the widget used for verification. |
| `status` | string | Current session status, such as `success`. |
| `selected_country` | string | Selected country code, e.g. `NG`. |
| `selected_id_type` | string | Identity document type selected by the user. |
| `created_at` | datetime | Session creation time in ISO 8601 format. |
| `completed_at` | datetime or null | Completion time, or `null` if not completed. |

### 2. Biometric scores

| Field | Type | Description |
| :- | :- | :- |
| `confidence_score` | number or null | Confidence score returned by the verification process. |
| `liveness_score` | number or null | Score returned by the liveness process. |

Scores should be interpreted according to LumiID's configured scoring thresholds. Do not assume they are percentages or that a particular value means a pass unless the scoring rules establish that.

### 3. Verification checks — `checks`

| Field | Type | Description |
| :- | :- | :- |
| `face` | boolean | Face check result. |
| `liveness` | boolean | Liveness check result. |
| `spoof` | string | Anti-spoofing result, e.g. `PASSED`. |
| `match` | boolean | Face or identity match result. |
| `match_band` | string | Match classification, e.g. `MATCH`. |
| `device_risk` | object | Device-related risk indicators. |
| `timing_risk` | object | Timing-related risk evaluation. |

The `device_risk` object can include:

* `suspicious_label`: indicates whether a suspicious device label was detected.
* `resolution_mismatch`: indicates whether a resolution mismatch was detected.

The `timing_risk` object can include:

* `evaluated`: indicates whether the timing-risk check was evaluated.

These individual checks should be interpreted together with the overall session status and your business rules.

### 4. Government identity data — `gov_data`

This object contains the government identity data returned by the relevant verification provider. example below uses Nigerian BVN

| Field | Type | Description |
| :- | :- | :- |
| `bvn` | string | Bank Verification Number, when returned. |
| `firstname` | string | First name. |
| `lastname` | string | Last name. |
| `middlename` | string | Middle name, which may be empty. |
| `birthdate` | string | Date of birth in the returned format. |
| `gender` | string | Gender returned by the provider. |
| `phone` | string | Phone number, when returned. |
| `photo` | string | Base64-encoded image data, when returned. |

The fields available inside `gov_data` depend on the identity type and provider response. Clients should handle missing, empty or additional fields safely.

Handling the photo: The `photo` value is Base64-encoded image data, not a regular image URL. Decode it on your backend or construct a suitable data URI for display when appropriate. Avoid logging or unnecessarily storing biometric images.

### 5. Webhook status

| Field | Type | Description |
| :- | :- | :- |
| `webhook_delivered` | boolean | Indicates whether the webhook was marked as delivered. |

This field reports webhook delivery state; it does not independently confirm that the user's identity verification passed.

## Error responses

### `401 Unauthorized`

Returned when the API key is missing or invalid.

```json theme={null}
{
  "error": "Invalid or missing API key."
}
```

### `404 Not Found`

Returned when the session does not exist or the authenticated API key's organization does not have access to it.

```json theme={null}
{
  "error": "Session not found or access denied."
}
```

### Other errors

Requests may also encounter framework-level or infrastructure errors. Clients should handle unexpected non-2xx responses gracefully.

## Integration example — Python

```python theme={null}
import requests

def get_session_result(api_key: str, session_id: str) -> dict:
    url = (
        "https://api.lumiid.com/api/v1/widgets/sessions/"
        f"{session_id}/result/"
    )

    response = requests.get(
        url,
        headers={
            "Authorization": f"Bearer {api_key}",
            "Accept": "application/json",
        },
        timeout=30,
    )

    if response.status_code == 401:
        raise PermissionError("Invalid or missing LumiID API key.")

    if response.status_code == 404:
        raise LookupError("Session not found or access denied.")

    response.raise_for_status()
    return response.json()


result = get_session_result(
    api_key="YOUR_LUMIID_API_KEY",
    session_id="f23bd55e-fbe5-4e48-a374-ee7203d240e0",
)

print("Session status:", result["status"])
print("Identity data:", result.get("gov_data", {}))
print("Verification checks:", result.get("checks", {}))
```

## Integration example — React.js

Recommended: Call LumiID from your backend in production so your secret API key is never exposed in browser code. The following example assumes your backend exposes a protected proxy endpoint.

```javascript theme={null}
import { useState } from "react";

export default function SessionResult({ sessionId }) {
  const [result, setResult] = useState(null);
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);

  async function fetchResult() {
    setLoading(true);
    setError("");

    try {
      const response = await fetch(
        `/api/lumiid/sessions/${sessionId}/result/`,
        {
          method: "GET",
          headers: {
            Accept: "application/json",
          },
          credentials: "include",
        }
      );

      const data = await response.json();

      if (!response.ok) {
        throw new Error(data.error || "Failed to retrieve result");
      }

      setResult(data);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  }

  return (
    <div>
      <button onClick={fetchResult} disabled={loading}>
        {loading ? "Loading..." : "Get verification result"}
      </button>

      {error && <p role="alert">{error}</p>}

      {result && (
        <div>
          <p>Status: {result.status}</p>
          <p>Country: {result.selected_country}</p>
          <p>ID Type: {result.selected_id_type}</p>
          <p>Face Match: {String(result.checks?.match)}</p>
        </div>
      )}
    </div>
  );
}
```

The `/api/lumiid/...` URL is your own backend route, not a LumiID endpoint. Your backend should call LumiID with the Bearer token and authenticate the requesting user.

## Integration example — PHP

This example uses PHP cURL and retrieves the result directly from LumiID. Run it on your server.

```php theme={null}
<?php

$apiKey = getenv('LUMIID_API_KEY');
$sessionId = 'f23bd55e-fbe5-4e48-a374-ee7203d240e0';

$url = 'https://api.lumiid.com/api/v1/widgets/sessions/'
     . rawurlencode($sessionId) . '/result/';

$ch = curl_init($url);

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPGET => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . $apiKey,
        'Accept: application/json',
    ],
    CURLOPT_CONNECTTIMEOUT => 10,
    CURLOPT_TIMEOUT => 30,
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ($response === false) {
    error_log(curl_error($ch));
    curl_close($ch);
    http_response_code(502);
    exit(json_encode(['error' => 'Unable to reach LumiID']));
}

curl_close($ch);

http_response_code($httpCode);
header('Content-Type: application/json');
echo $response;
```

Set `LUMIID_API_KEY` in your server environment. Do not hardcode your production key into a publicly accessible PHP file or commit it to source control.

## Integration example — Flutter (Dart)

Add the HTTP package:

```json theme={null}
flutter pub add http
```

Create a service to retrieve the result:

```dart theme={null}
import 'dart:convert';
import 'package:http/http.dart' as http;

class LumiIDService {
  final String apiKey;

  LumiIDService({required this.apiKey});

  Future<Map<String, dynamic>> getSessionResult(
    String sessionId,
  ) async {
    final uri = Uri.https(
      'api.lumiid.com',
      '/api/v1/widgets/sessions/$sessionId/result/',
    );

    final response = await http.get(
      uri,
      headers: {
        'Authorization': 'Bearer $apiKey',
        'Accept': 'application/json',
      },
    );

    final data = jsonDecode(response.body);

    if (response.statusCode != 200) {
      throw Exception(
        data is Map<String, dynamic>
            ? data['error'] ?? 'Failed to retrieve session result'
            : 'Failed to retrieve session result',
      );
    }

    return Map<String, dynamic>.from(data);
  }
}
```

Example usage:

```dart theme={null}
final lumiid = LumiIDService(apiKey: yourApiKey);

try {
  final result = await lumiid.getSessionResult(
    'f23bd55e-fbe5-4e48-a374-ee7203d240e0',
  );

  print('Status: ${result['status']}');
  print('Government data: ${result['gov_data']}');
  print('Verification checks: ${result['checks']}');
} catch (e) {
  print('Error: $e');
}
```

Security note: Do not bundle a permanent secret API key in a production Flutter app. Use your authenticated backend as a proxy.

## Recommended integration workflow

1. Create a verification session using your LumiID widget.
2. Register a webhook URL when configuring the widget to receive session results after completion.
3. Use the session ID to retrieve the full result from your backend when needed.
4. Validate the session status and individual checks before making an onboarding decision.
5. Store sensitive identity data securely and retain it only as necessary.


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