Vehicle assessments

The vehicle assessment sandbox turns a set of photographs into one editable condition record. It is enabled per customer-owned appraisal policy. It does not create charges or send messages. Existing mobile SDK verification methods remain unchanged; this workflow uses the REST API below.

Authenticate every request using X-API-Key with an existing Verify AI key. Use the base URL https://verify.switchlabs.dev/api/v1/vehicle-assessments.

Pricing and production access

The public vehicle appraisal rate is $2.00 per completed appraisal, including up to 16 original photos and detailed analysis. This is separate from Standard and Advanced single-photo API pricing. See the full appraisal offer.

The endpoints documented here remain an unbilled evaluation sandbox. Contact sales to arrange production access and terms. The sandbox upload limit of 24 photos is a technical limit, not the 16-photo public allowance; larger production photo sets require a quote.

Create a vehicle assessment

POST /api/v1/vehicle-assessments

json
{
  "id": "70dfe4c6-5267-46f7-bced-1799afad5319",
  "policy_id": "<your enabled appraisal policy>",
  "vehicle_ref": "Stock 1042"
}

Generate a new UUID for each vehicle. Reusing that UUID retries creation safely. The response includes id, revision, document, and a derived summary. GET /api/v1/vehicle-assessments lists the account's assessments, enabled policies, saved repair matrices, and previous uploads.

Inspection criteria are snapshotted at creation (policy_snapshot_at). Editing a policy does not change an existing assessment, including its later detail analysis. Create a new assessment to use revised criteria. Deleted assessment IDs cannot be reused.

Upload original photos

POST /api/v1/vehicle-assessments/{id} with the current revision:

json
{
  "revision": 0,
  "action": "register_photo",
  "id": "8b6b005e-d433-4e93-934e-5d52da63cfbb",
  "name": "front-left.jpg",
  "slot": "front_left",
  "content_type": "image/jpeg"
}

The response contains an updated assessment and upload.url. PUT the original file bytes to that signed URL using its image Content-Type. Do not send your Verify AI key to the storage URL. The URL authorizes only that new object. Upload JPEG, PNG or WebP files up to 20 MB and 50 megapixels, with up to 24 photos per assessment. Originals are stored privately; read URLs expire after one hour and are refreshed by GET.

Valid purposes: front, front_left, left, rear_left, rear, rear_right, right, front_right, wheel_fl, wheel_fr, wheel_rl, wheel_rr, detail, odometer, vin, and overview. Left and right are the vehicle's sides from the seated driver's perspective. VIN and odometer photos return readings, not body-condition findings.

Analyze each photo

POST to the same assessment URL:

json
{
  "revision": 1,
  "action": "analyze_photo",
  "photo_id": "8b6b005e-d433-4e93-934e-5d52da63cfbb",
  "depth": "standard",
  "request_id": "2216ca33-2c42-4d5d-bd9f-fb0f3116ba9d"
}

standard assesses the photograph once. detailed additionally inspects four overlapping crops of sufficiently large exterior views, with two detail requests in flight at once. Small source images cannot recover detail through cropping. No confidence probability or automatic physical millimetre measurement is returned.

Photo states are uploaded, analyzing, accepted, retake, review, and error. A clear photograph of damage is accepted. Unclear evidence is flagged for a new photograph or review. Partial detail-pass failures remain visibly marked for review. A completed analysis can be replayed without making another model call. Failed requests permit up to three attempts per photo; abandoned analysis leases become retryable after five minutes.

Upgrade and recover analysis

To upgrade a standard result, send depth: "detailed" for the same photo ID, with the current revision and a new UUID request_id. Eligible exterior originals have a longest edge of at least 1400 pixels; VIN, odometer and close-up purposes do not receive grid crops. Only the four detail regions run. Previous observations and reviewed findings are preserved; new findings start unreviewed.

If document.photos[].failed_regions is nonempty, send depth: "detailed", retry_failed: true, and a new request_id. Only those failed regions run; successful regions remain unchanged. A region that was analyzed but needs a clearer photograph is not a failed request. Add a close-up for that case. Each photo permits three initial attempts and three additional detail attempts.

Reusing a completed request_id with the same intent returns the saved result, including a saved partial failure, without another analysis call. Reusing it with different depth or retry intent is rejected. After a partial failure, use a new ID to request another attempt. A detail upgrade/recovery requires a current revision; an ordinary completed replay may use its original revision. While analysis is running, pending_analysis contains its request ID, depth and retry intent. After a five-minute abandoned lease, resend that intent with the current revision; the workspace Retry analysis control does this automatically.

Sandbox allowance

Responses include usage with mode: "sandbox", billable: false, units_used, units_limit, and resets_at. The default allowance is 1,000 analysis units per account per UTC day, shared by portal and API use. One response attempt uses one unit. Standard normally uses one; detailed normally uses five on eligible originals, or four when upgrading. A malformed-response retry uses another unit. Completed replays do not consume units.

The allowance is checked atomically before each response attempt. If exhausted, unfinished analysis remains retryable after the UTC reset. Timeouts and malformed responses can consume units. These endpoints remain an unbilled evaluation sandbox; using a production API key does not establish paid production access or a production pricing contract.

Review and correct

Every mutation includes the most recent revision. Stale edits receive HTTP 409; GET the assessment and reconcile before retrying. Never replace the entire document with a client copy.

Supported actions:

ActionAdditional fields
renamevehicle_ref
edit_findingfinding_id, finding
add_findingphoto_id, bbox, finding
mergesource_id, target_id
unmergefinding_id
mark_distinctfirst_id, second_id
exclude_photophoto_id, excluded (boolean)
apply_matrixmatrix_id or null

A finding contains panel, damage_type, severity, description, size_class, and status. Severity is light, medium or severe; status is unreviewed, accepted or dismissed. A size band is unknown, small, medium or large using the appraiser's own definitions. It is supplied by the reviewer, never inferred as a physical measurement.

Boxes use [left, top, right, bottom] fractions of the EXIF-oriented original image. Distinct observations are preserved in document.photos[].observations; corrections live in document.findings. Merge actions retain all original evidence and can be reversed. Photo exclusion is reversible and does not erase original observations. The history records changes.

Apply your repair matrix

POST /api/v1/vehicle-assessments/matrices with JSON { "name": "Workshop prices", "csv": "..." }. The result returns a new immutable matrix ID and version. Apply that ID to any assessment in the same account. Importing a newer matrix does not silently change older assessments.

Download the CSV template. Its empty amount is intentional: supply your actual price before importing.

ColumnValues
panelA panel ID from the assessment's coverage, or *
damage_typescratch, scuff, dent, paint_chip, paint_transfer, kerbing, flat_tyre, tyre_damage, misalignment, crack, broken, missing, rust, glass_damage, other, or *
severitylight, medium, severe, or *
size_classunknown, small, medium, large, or *
amountNon-negative amount in major currency units, at most two decimal places
currencyOne supported three-letter currency with two decimal places throughout the file (for example EUR, GBP or USD)
repair_methodYour repair operation name
charge_basisper_panel or per_finding

An exact panel match takes precedence, then damage type, severity, and size. Explicit * rules provide fallbacks. No matching rule means unpriced, not zero. Duplicate rule signatures are rejected. A per_panel rule charges the largest matching amount once per panel and repair method; per_finding charges each finding. Tax treatment is whatever your supplied amounts represent.

Retrieve and export

  • GET /api/v1/vehicle-assessments/{id} returns the saved JSON, evidence links, review history, matrix snapshot and summary.
  • GET /api/v1/vehicle-assessments/{id}/pdf returns the condition report.

Coverage distinguishes assessed, partial and not-inspected panels. The observed K grade uses the Verify AI default grading scale and covers visible evidence only. Review counts, incomplete photos, possible duplicates and unpriced findings remain explicit. This sandbox does not send completion webhooks; retrieve the saved record after analysis.

Retention and deletion

An assessment's expires_at is null unless a retention period was explicitly configured. A policy may set vehicleAssessmentRetentionDays (1–3650) for new assessments. Existing records are unaffected by later policy changes.

POST { "action": "set_retention", "revision": 4, "days": 30 } to set deletion eligibility 30 days from now, or days: null to retain until explicitly deleted. The change is recorded in review history. The workspace exposes the same controls.

POST { "action": "delete_assessment", "revision": 5, "confirmation": "Stock 1042" } with the exact vehicle reference to request deletion. The assessment immediately disappears from normal reads and rejects further edits/analysis. Already issued image URLs can remain usable until their one-hour expiry. Copied originals, the report, observations and review history are permanently removed by the background worker after a minimum 24-hour delay; the daily processing window can add up to another day. Automatic expiry uses the same queue. Storage failures leave the deletion job retryable.

Deletion covers this assessment's copies, not source images in previous sandbox uploads or separately saved price matrices. Export any required records before requesting deletion. Deletion requests cannot be reversed through the API.

Get in Touch

Questions about pricing, integrations, or custom deployments? We'd love to hear from you.