Joshua Shepelsky

Trail map of what I've built

Most difficult trail to Estimate Ridge

Collision Estimate AI

An API that turns damage photos into a line-item collision repair estimate, and explains insurance estimates in plain language, in 16 languages.

Damage photosAPI GatewayS3 uploadsClaude on BedrockLine itemsEstimate RidgeTrailhead
16 output languages at the summitRide it on the map
Role
Sole engineer, on contract for Assurity Certified Solutions
When
2026
Status
In production behind the free AI tools on collisionrepairlocator.com

13

Lambda functions in one CDK stack

16

output languages for the translator

6

photos max, numbered line items out

51

tax locales (50 states + DC)

Architecture

  1. Clients

    • Locator: instant estimator + translator
    • Partner apps with an API key
  2. Edge

    • API Gateway: throttling + usage plan
    • Lambda authorizer: keys in DynamoDB
  3. Pipeline

    • Presigned S3 uploads
    • VIN decode via NHTSA vPIC
    • Async jobs with retry
  4. Model

    • Claude on Amazon Bedrock
    • Forced tool call = schema-guaranteed output
  5. Output

    • Estimates + review queue
    • PDF invoices
    • Translations in 16 languages
    • Usage + cost per key
One CDK stack. Clients never touch the model directly, and every call is metered to an API key.

The problem

A collision repair estimate is a wall of jargon. R&I, blend, betterment, sublet. Drivers get one from an insurer and have no idea what they’re looking at. Shops want a fast preliminary number before a car rolls in. And there was no proprietary estimate dataset to train a model on.

So the goal was an API that gives an honest first answer, structured like a real shop estimate, that other products can build on.

What I built

Two flows behind one API.

Estimates. You upload up to six damage photos plus the year, make, and model, or just a VIN. The API decodes the VIN through NHTSA’s vPIC service and pins the exact body style, drivetrain, and engine. Then Claude on Amazon Bedrock looks at the photos and returns numbered line items: operation, part, part type and price, labor hours and rate, and category totals for parts, labor, paint, materials, calibration, frame, and sublet. The result comes back as JSON and as a printable PDF invoice.

Translations. You upload an insurance or shop estimate as a PDF or photos and get a plain-language walkthrough of the work, the costs, and the terms, in any of 16 languages. Each language renders once and is cached, so switching languages is instant after the first request.

How it’s put together

Everything lives in one AWS CDK stack and deploys with one command:

  • 13 Node.js Lambda functions behind API Gateway: upload URLs, async estimate and translation pipelines with retry, PDF rendering, an admin router, and a request authorizer
  • The authorizer checks every x-api-key against a managed key store in DynamoDB, with a 5-minute cache and a break-glass key
  • Photos go straight to S3 through presigned URLs
  • Config lives in Secrets Manager and Parameter Store, and admin sign-in runs through Cognito
  • The Swagger docs come from the same OpenAPI document the gateway serves, so the docs can’t drift from the API

Decisions that mattered

Forced tool calls instead of “please return JSON.” The model answers through the Bedrock Converse API with a forced tool call, so every estimate matches the schema and there’s nothing to clean up with regex.

Honest framing. Every estimate is a preliminary range with a confidence level and a disclaimer. Part prices are model estimates, not catalog prices, and the docs say so plainly.

Everything hangs off the API key. Each key carries usage counts, cost, limits, and its own shop labor rates and tax locale. A partner integrates once and stops resending config. The Assurity management portal shows every key’s usage and spend.

Screen inputs during the model run. Photos that don’t show a vehicle fail with REJECTED_NOT_A_VEHICLE. Uploads that aren’t an estimate fail with REJECTED_NOT_AN_ESTIMATE. Unsafe content fails and the files are deleted from S3. Those failures are final, so retries can’t burn money on them.

There was no training data at the start, so every estimate also lands in an admin review queue. Reviewer feedback is how the dataset gets built.

Where it runs

The API powers the free Instant Estimator and Estimate Translator on collisionrepairlocator.com. Drivers use them without an account. They verify an email or phone number first, and nothing goes to the model until that check passes.

What’s next

Reviewer edits to individual line items, role-based admin access, and catalog-backed parts pricing.

esc
↑↓ move↵ openesc close

Ranger station

Claude Haiku, answering from this site's write-ups

Ask about Josh's work: the case studies, his background, and his stack. Or try one of these:

AI can be wrong. For anything important, email Josh.0/600