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,reviewfrom(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.