Valara

Review lifecycle

The asynchronous submit, poll, fetch job model, plus idempotency and caching.

A review takes minutes, not milliseconds, so the API never blocks on one. You submit a review, track its progress (stream or poll), then fetch the result. This is the contract agents and integrations should build against.

Statuses

GET /api/v1/reviews/{id} reports one of four statuses:

StatusMeaning
processingThe review is running. Keep polling.
completedDone. Fetch the result at /reviews/{id}/result.
failedThe review could not be completed.
cancelledThe review was superseded or cancelled.

Tracking progress

You can either stream progress or poll for it. Both read the same durable run, so neither restarts the work and a dropped connection never loses progress.

Stream (preferred)

GET /api/v1/reviews/{id}/events is a Server-Sent Events stream of progress events. It stays open while the review is processing and closes when the review reaches a terminal state, so a client reacts the moment the review finishes instead of waiting for the next poll. After a dropped connection, reconnect with ?start_index=N to resume from an event offset.

The stream exists only for a processing review. Once the review is completed, failed, or cancelled, the endpoint returns 404; fetch the result instead.

Poll (fallback)

When a long-lived connection is inconvenient (serverless callers, simple scripts), poll GET /api/v1/reviews/{id} every few seconds until the status is completed or failed.

Idempotency by content hash

A review's id is the SHA-256 content hash of the appraisal PDF. Submitting the same bytes twice refers to the same review, so retries are safe by construction and you never pay twice for the same appraisal.

This is why submit has two success codes:

CodeWhen
202 AcceptedA new review started. status is processing.
200 OKThat appraisal was already reviewed. The completed review is returned immediately.

A client can treat both the same way: read status, and if it is not yet completed, poll.

Submitting

POST /api/v1/reviews accepts two transports:

  • Raw PDFContent-Type: application/pdf with the file as the body and review_type / filename in the query string. Best for large reports.
  • JSON{ "blob_url", "filename", "review_type" } referencing an already-uploaded file.

review_type is an explicit enum (residential or commercial); the API does not auto-classify. It defaults to residential when omitted.

Deleting

DELETE /api/v1/reviews/{id} removes a review and returns 204 No Content. Requires the reviews:delete scope.

Fetching results

Once completed, GET /api/v1/reviews/{id}/result returns the scored result. Calling it before completion returns 404 not_found — poll status first. The result shape is a discriminated union on review_type; see the result schema.

On this page