LaneScan API v1

Pull road-marking audits, segments, quotes and reports into your own systems, and create quotes and jobs. Every request is scoped to the organisation that owns the API key.

Authentication

An organisation admin creates a key in Settings → API. It is shown once; LaneScan stores only a SHA-256 hash. Send it on every request:

curl https://YOUR-LINESCAN-DOMAIN/api/public/v1/audits?status=complete \
  -H "x-api-key: lsk_..."

Read-only keys can call every GET. Creating quotes and jobs needs a key with read + write access.

Limits and errors

60 requests per minute per key. Responses include x-ratelimit-limit, x-ratelimit-remaining and x-ratelimit-reset; over the limit you get 429 with retry-after.

{ "error": { "code": "not_found", "message": "Audit not found" } }

Image and PDF links are signed and expire after 10 minutes — fetch a fresh one when needed.

Endpoints

GET/v1/audits

List audits

  • status (query) — Comma-separated, e.g. complete,review
  • from (query)
  • to (query)

GET/v1/audits/{id}

Get an audit with its summary

  • id (path) — Audit id (UUID)

GET/v1/audits/{id}/segments

Audit segments as GeoJSON

  • id (path) — Audit id (UUID)
  • class (query) — Comma-separated classes: good,fair,poor,missing,needs_review,unpaved,unusable

GET/v1/segments/{id}

Get a segment with frame image URLs (valid 10 minutes)

  • id (path) — Segment id (UUID)

POST/v1/quotes

Create a draft quote from segments (needs a read + write key)

GET/v1/quotes/{id}

Get a quote with its lines

  • id (path) — Quote id (UUID)

POST/v1/jobs

Create a job from a quote (needs a read + write key)

POST/v1/jobs/{id}/verify

Create the verification audit shell (needs a read + write key)

  • id (path) — Job id (UUID)

GET/v1/jobs/{id}/certificate

Signed completion-certificate PDF URL (valid 10 minutes). 404 not_generated until an admin or reviewer generates it in LaneScan.

  • id (path) — Job id (UUID)

GET/v1/reports/{id}/download

Signed PDF download URL (valid 10 minutes)

  • id (path) — Report id (UUID)
POST /api/public/v1/quotes
{ "segment_ids": ["9b1c…", "a4e2…"], "client_name": "Mayor & City Council" }

POST /api/public/v1/jobs
{ "quote_id": "…", "external_ref": "HUB-1042" }

Webhooks

Admins add an https URL in Settings → API and choose events: audit.completed, review.completed, quote.created, verification.completed. Each webhook gets its own signing secret (shown once).

POST https://your-url
x-linescan-signature: sha256=<hex HMAC-SHA256 of the raw body>
x-linescan-event: verification.completed
x-linescan-event-id: 3f0c…

{ "event": "verification.completed", "id": "3f0c…", "organization_id": "…",
  "occurred_at": "2026-11-05T17:00:00Z", "data": { "job_id": "…", "external_ref": "HUB-1042", "summary": { … } } }

Verify the signature before trusting the body (Node.js example):

const expected = "sha256=" + crypto.createHmac("sha256", SECRET).update(rawBody).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers["x-linescan-signature"]));

Reply with any 2xx within 10 seconds. Otherwise LaneScan retries 5 times, after 1, 5, 15, 60 and 240 minutes. Use the event id to ignore duplicates.