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

# Staged

> Building a submission up from documents you already hold, a call at a time.

For a workflow whose `mode` is `staged`. The documents reached you through your own onboarding, so
there is nobody to send to a journey: you upload what you hold, send the values the steps take, and
ask for the checks to run.

```mermaid theme={"system"}
sequenceDiagram
    autonumber
    participant App as Your backend
    participant API as Privue

    App->>API: create a verification
    API-->>App: id
    loop once per document
        App->>API: upload a file, naming its step and slot
    end
    App->>API: run the checks, with the values the steps take
    API-->>App: accepted, run_requested_at set
    Note over API: reads each document, confirms it at source, cross-checks the names
    API-->>App: callback when it is submitted
    App->>API: read the record
```

Three calls: create, upload each file, run. For runnable code, see
[Recipes](/verification/recipes/staged); for request and response shapes, the
**API reference** tab.

A workflow whose `mode` is `instant` is answered in a single call instead, with the result in the
reply; see [Instant](/verification/instant). A workflow is configured for one or the other.

## Creating

`POST /verifications` takes the `workflow_key`, your `reference_user_id` and any `context`, and nothing
else. There is no user to sign in, so a call that names a `mobile` or a `return_url` is refused with
`400`, and the record comes back with `mobile`, `return_url` and `journey_url` all null.

Creating is idempotent on your reference: the same `reference_user_id` in the same workflow always
resolves to the same verification, answering `200` instead of `201`, until that verification expires.
See [Verification lifecycle](/verification/lifecycle#creating-a-verification) for the rest.

## Addressing a document

Every step a staged workflow declares is one you can answer. The types the person being verified
answers themselves, `selfie`, `premises-photos`, `digilocker` and `review`, belong to a hosted
workflow and are never declared on a staged one.

A file is uploaded against the step it belongs to and the slot on that step it answers. Reading the
workflow names both: `intake.slots` lists the slots, each saying whether it is required and which kinds
of document satisfy it, and `intake.values` names the values the step takes in the run request. A step
whose `intake` is empty on both counts is answered from what earlier steps established, and you send
nothing for it.

Every slot names the kinds of document that satisfy it, as a bank account proof takes a statement, a
cancelled cheque or a bank letter. Where a slot names several, send the `kind` alongside the file to
say which of them yours is; where it names one, your file is taken as that one. The files in one slot
are all of the same kind, because together they are one document.

Each kind says how it arrives, in its `accept`: how many files, in what formats. They differ within one
slot, since a cancelled cheque is one photograph and a statement is a document of several pages, so
read the shapes off the kind you are sending rather than off the slot.

A PDF may be up to 20 MB and an image up to 10 MB. A file the slot cannot take is refused on its own
call, `415` for the wrong format and `413` for one over the limit, and nothing else you uploaded is
affected.

The mode, the step keys and the intake are stable. They are how you address a document and a value, so
they do not change under a workflow you are integrated against. What a step is configured to check, and
which steps a workflow declares, we tune as a journey is refined. Each refinement is a new version of
the workflow, and a verification you have created keeps the version it was created on, so the steps you
upload to and ask to run are the ones it had when you created it.

## Correcting an upload

`DELETE /verifications/{verification_id}/documents/{document_id}` withdraws a file. It stops counting
towards its step and its slot has room again, so a wrong upload is corrected without resetting the
whole verification.

## What you decide, and what we do

You supply documents and values. You never say which order the checks run in, which steps this
particular subject needs, or when a step is finished. The workflow decides all three, and each step is
checked against what the steps before it established.

| You did this | We record |
| - | - |
| Uploaded a complete set of documents to a step | The step is answered with them |
| Sent values for a step | The step is answered with those |
| Gave an optional step nothing | The step reads `not-supplied` |
| Gave a required step nothing | The run request is refused, naming the step |
| Filled only part of a slot | The run request is refused, naming the slot and what it is short of |
| Sent values and a document for the same step | The run request is refused; the step verifies one or the other |

A step gated on what an earlier step publishes cannot be decided when you ask for the run, so it is not
checked then. If it turns out to apply and nothing arrived for it, it reads `not-supplied`, required or
not.

There is no separate step to confirm a document, and nothing to submit at the end. Asking for the
checks to run is the whole of it.

## The run request freezes the submission

`POST /verifications/{verification_id}/run` records your request on the verification as
`run_requested_at` and returns at once. From that moment the submission is frozen: an upload, a
withdrawal, or another run request with different values is refused with `409` until you reset. Sending
the same run request again is safe; it names the run already in progress and changes nothing.

Reading each document and confirming it with the issuing body takes longer than a request should be
held open, so the record comes back with `run_requested_at` set, the checks still to run and the status
still `open`. Wait for your [callback](/verification/callbacks), or poll until the status is
`completed`.

## When something is missing

A submission that cannot be run as it stands is refused with `422` before anything runs, so a document
you left out is answered by the call that left it out rather than by a verification that never
finishes.

```json theme={"system"}
{ "detail": "pan: nothing was supplied for this step" }
```

A slot you filled only part of is refused the same way, whether its step is required or not. A slot
that takes a certificate's pages as separate images is not answered by one of them, and files did
arrive for it, so treating it as a step you skipped would report the wrong thing.

```json theme={"system"}
{ "detail": "gst: slot 'gst-certificate' needs 2 more file(s)" }
```

A step given both values and a document is refused too, because the step verifies one of them and
choosing for you would silently drop the other. Values are checked the same way, naming the step and
the field at fault.

Nothing was charged for and nothing was checked. Correct the submission and ask again.

## When a source cannot be reached

A registry or bank being unreachable is not a verdict about the subject, so we do not record one as
though it were. The run keeps trying the submission for about an hour, and only once those attempts are
spent does the verification complete with that step reading `error`.

That is what distinguishes it from `failed`: a failed step was checked and did not stand up; a step in
`error` was never checked at all.

## Stopping, running again, and purging

Cancel ends the verification where it stands and stops a run still in progress. Reset clears every
answer, every file and the run request, and reopens the verification, so you upload and ask again.
Purge deletes everything you supplied and closes the record for audit. See
[Verification lifecycle](/verification/lifecycle#ending-or-restarting).


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