> This page is for version 🇦🇺 AU (default).
> For other versions, use one of these documentation indexes:
> - 🇦🇺 AU (default): https://docs.humanapproved.com/au/llms.txt
> - 🇬🇧 UK: https://docs.humanapproved.com/uk/llms.txt
> - 🇺🇸 US: https://docs.humanapproved.com/us/llms.txt

> This is HumanApproved's documentation, as Markdown for AI agents. /llms.txt lists every page; /llms-full.txt has them all. If you're helping someone integrate HumanApproved, start with /guides/ai-coding-agents.

# Checks and reviews

> How HumanApproved checks, outcomes, review statuses, expiry, decline reasons, results and product versions fit together.

## Checks

A **check** runs each time someone continues from the step you protect. It determines whether the purchase can proceed or needs the customer's approval first. The embed creates checks for you; from a server you create them yourself with `POST /api/v1/checks` and a publishable key.

A check needs only your quote reference (`quoteRef`, 1 to 128 characters). It carries no personal data. You can also send:

* `userId`: your own ID for this customer, so you can find their checks and approvals in the portal. See [userId](#userid).
* `signal`: your own detection result, for a product set to use it. See [Agent detection](/concepts/agent-detection).

Every call creates a new check. There's no idempotency key, so don't repeat a check that already returned: reuse its review.

### Outcomes

| `outcome`  | Means                                                                                                            | What to do                                                |
| ---------- | ---------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
| `continue` | No approval is needed.                                                                                           | Go ahead with the purchase.                               |
| `review`   | The customer must approve first. The response includes a `review` with its `id`, `token`, `url` and `expiresAt`. | Send the quote, show the link, and wait for the approval. |

Which outcome you get depends on the product's **When to ask for approval** setting: only when an agent is detected, every purchase, or never (monitor only, which always returns `continue`). The response never includes a score or the reasons behind it: they're shown in the portal.

## Reviews

A **review** is created when a check returns `review`. It's the customer's approval, or refusal, of one quote. Its approval link, `review.url`, is the page the customer opens. Use it exactly as given rather than building it: a product can have its own approval page address.

### Statuses

| `status`         | Means                                                                        |
| ---------------- | ---------------------------------------------------------------------------- |
| `awaiting_quote` | The review exists, but the quote and mobile haven't been sent yet.           |
| `pending`        | The quote was sent. Waiting for the customer.                                |
| `approved`       | The customer approved. Go ahead.                                             |
| `declined`       | The customer declined. Don't go ahead.                                       |
| `expired`        | The link expired before the customer answered. Start again with a new check. |

```mermaid
flowchart LR
    aq["awaiting_quote"] -->|quote sent| p["pending"]
    p -->|approves| a["approved"]
    p -->|declines| d["declined"]
    p -->|time runs out| e["expired"]
```

A review starts as `awaiting_quote` when a check returns `review`, and can also expire there if the quote never arrives. Follow a review with `GET /api/v1/reviews/{reviewId}/status` and its token; read the full outcome from your server with your secret key. See [Verify on your server](/guides/verify-on-your-server).

### Sending the quote

Send the quote and the customer's mobile once, while the review is `awaiting_quote`, with `PUT /api/v1/reviews/{reviewId}/quote` and the review's token. The quote must match the fields of the product version the review uses: fields the version doesn't define are dropped, and a missing or wrongly typed field is refused with `422 invalid_quote`. A second send gets `409 quote_already_set`: treat the quote as sent.

### Expiry

A review's link lasts 24 hours unless the product sets another time, from 15 minutes to 7 days, on its **Approval settings**. `expiresAt` tells you when. After that the review is `expired`, and the quote can no longer be sent (`410 review_expired`). A product's identity check can also expire a review early, after too many wrong answers. See [Approval methods](/concepts/approval-methods).

### Decline reasons

When a customer declines, they can say why. The status call returns the reason as `declineReason`, with its `code` and the `label` exactly as the customer saw it, so you or the embed can tell the agent why. It's `null` when no reason was given.

| `code`          | `label` the customer sees |
| --------------- | ------------------------- |
| `not_me`        | I didn't ask for this     |
| `details_wrong` | Some details are wrong    |
| `changed_mind`  | I've changed my mind      |
| `other`         | Another reason            |

The outcome your server reads has `declineReason` as the code alone, and `declinedAt`.

## Results

When the purchase ends, report what happened with `POST /api/v1/checks/{checkId}/result`. The embed does this for you.

| `result`    | Send it when                                                                      |
| ----------- | --------------------------------------------------------------------------------- |
| `completed` | You proceeded after `continue`, or after the customer approved.                   |
| `fail_open` | You proceeded without a response, for example because the check timed out.        |
| `abandoned` | You didn't go ahead: the review was declined or expired, or the customer gave up. |

Only the first result for a check is kept, so retrying is safe.

## Product versions

You edit a product as a draft and publish it as a numbered version. Checks always use the version that's live when they're made, and a review keeps that version for its whole life: its approval page, its fields and its rules don't change if you publish again while the customer is reviewing. The outcome's `productVersion` tells you which version the customer saw.

A product with no published version can't be checked: checks are refused with `409 product_not_live`.

## userId

`userId` is your own ID for the customer, such as a customer or account number, up to 128 characters. You can then search for that customer's checks and approvals in the portal, and the outcome your server reads includes it.

> **Warning**
>
> Use an opaque ID from your own system. Don't use an email address, phone number or name. If the value looks like an email address or phone number, it isn't stored. `userId` is never sent back to the page.