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

# Concepts

> Workspaces, verifications, attempts, external IDs and the difference between test and live.

## Workspace

A workspace is one integration. It fixes:

* **The check**, called **Verification** in the console: **Identity (KYC)**, or **Age verification** with one of two methods: **ID document** (minimum age 16 to 25) or **Facial age estimation** (18+). In the API: `flow_type` `kyc` or `age`, and on age workspaces `age_mode` `document_verification` or `estimation` with `age_threshold`. See [the home page](/).
* **The mode**: test or live, chosen at creation and never changed.
* **The keys**: a public key that identifies the workspace, and up to five secret keys that sign requests. See [Workspaces and keys](/console/workspaces-and-keys).
* **Settings**: the webhook URL, the default redirect URL, whether expired documents are accepted and whether one face may verify under several of your users.

Create one workspace per product or environment. A test and a live workspace are two separate workspaces with separate keys.

## Verification

A verification is one person going through the check once; the widget and the SDKs call it a session. Your backend creates it, gets its `id` and a `url`, and the person completes it at that `url`. It moves through statuses until it reaches a final one:

| Status | Meaning | Final | Webhook |
| - | - | - | - |
| `created` | The verification exists; no image has been uploaded yet. | No | No |
| `started` | The person is capturing: the selfie is in, or on Identity (KYC) both sides of the document are. | No | No |
| `documents_required` | A facial age estimation could not confirm 18+ from the selfie; the person adds an identity document. Reported by `GET` only. | No | Yes, as `resubmission_requested` with `reason: null` |
| `submitted` | The images are in and are being analysed. | No | No |
| `review` | The verification waits for a person's decision. Test workspaces always stop here. | No | Yes |
| `resubmission_requested` | Something must be captured again; the person retries in the same verification. | No | Yes |
| `approved` | The verification passed. | Yes | Yes |
| `declined` | The verification failed; `reason` says why. | Yes | Yes |
| `abandoned` | Started, or asked to resubmit, and then no progress for 7 days. | Yes | Yes |
| `expired` | Never started within 7 days of being created. | Yes | Yes |

The full state diagram is on [Verification statuses](/integration/verification-statuses).

## Attempt

Inside one verification, each try at the capture is an attempt. When the person is asked to retake an image (`resubmission_requested`), a new attempt starts in the same verification, with the same `url`. When a facial age estimation needs a document, the document is added to the same attempt. The number of attempts is limited. When they run out the verification is `declined`, and its `reason` is the last attempt's reason, not a separate code: treat `declined` as final whatever the code.

Results you read back name the attempt they come from, as `attempt_id` or `meta.attempt_id`. You rarely need it: the verification's status and reason always describe the attempt that decided it.

## Your identifiers

| Field | Sent | Returned in API and webhooks | Use it for |
| - | - | - | - |
| `external_id` | On create, signed requests only | Yes | Your user's ID, to match the decision to the person. |
| `external_metadata` | On create | Yes, as sent | Context you want back, such as a plan or order ID. It is accepted without a signature, so do not trust it for decisions. |
| `metadata` | On create | No | Internal notes kept on the verification. |

`external_id` also scopes [duplicate detection](/core-technology/duplicate-detection): the same face under a different `external_id` is a possible duplicate account.

## Test and live

| | Test workspace | Live workspace |
| - | - | - |
| Keys | `pk_test_…` / `sk_test_…` | `pk_live_…` / `sk_live_…` |
| Analysis | None: a submitted verification goes straight to `review`. | Every check of the workspace type runs. |
| Outcome | You set it: on the verification's page in the console, with the MCP tool `set-test-verification-outcome`, or with `POST /v1/verifications/{id}/test-outcome`. | Decided by the checks, or by a person for `review`. |
| Billing | Never billed. | Billed per submitted verification. |
| Mode | Fixed when the workspace is created. | Fixed when the workspace is created. |

Build against a test workspace, then [go live](/integration/go-live) by creating a live workspace and swapping its keys into your configuration.


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