Complete iQ Inspect

Developers · API v1.1.0

Complete iQ Inspect public API

Create vehicle inspections from your own systems, follow their progress with signed webhooks, and pull released reports and photos. Agents can use the same capabilities through the MCP server.

Quickstart

  1. An administrator creates an API key in Settings → API & Webhooks. The full key is shown once.
  2. Create an inspection. The link goes to the claimant by text, email or both.
  3. Add a webhook endpoint in the same settings page, or poll the inspection's status.
  4. Once an administrator releases the report, fetch it as JSON or PDF along with the photos.
curl -X POST https://inspection360.ai/api/v1/inspections \
  -H "Authorization: Bearer $CIQ_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: clm-1042-initial" \
  -d '{
    "claimNumber": "CLM-1042",
    "claimantFirstName": "Jordan",
    "claimantLastName": "Lee",
    "phone": "+13055550142",
    "deliveryChannel": "sms"
  }'

The response (HTTP 201) includes the inspection id, its status (sent once the message goes out), the handlingTrack and the link. Check on it any time:

curl https://inspection360.ai/api/v1/inspections/$INSPECTION_ID \
  -H "Authorization: Bearer $CIQ_API_KEY"

Authentication

Send your key as Authorization: Bearer ciq_sk_live_… or in the x-api-key header. Keys belong to one organization, are stored only as a hash, and carry one or both scopes:

  • inspections:read for status, reports, photos and templates
  • inspections:write for creating inspections

Base URL: https://inspection360.ai/api/v1

Endpoints

Generated from the OpenAPI specification. Download it for the full request and response schemas.

POST /inspections

Trigger an inspection workflow

Creates a claim + inspection request for the authenticated organization and (by default) delivers the magic link to the claimant by SMS or email. Pass an `Idempotency-Key` header to make retries safe.

Scope: inspections:write

Parameters
Name Type Description
Idempotency-Key header · string Replays the original response if the same key is reused.
Request body
Name Type Description
claimantFirstName required string
claimantLastName required string
claimNumber required string
lossType "vehicle"
deliveryChannel "sms" | "email" | "both" Defaults to email if email provided, else sms. Use "both" to deliver by SMS and email together (requires both phone and email).
phone string Required if deliveryChannel is sms or both.
email string (email) Required if deliveryChannel is email or both.
templateId string (uuid) Optional; uses the org's configured active default template for the loss type if omitted, falling back to the most recent active template.
propertyAddress string The loss location for the claim.
vehicleDescription string
descriptionOfLoss string
handlingTrack "express_auto" | "express_assist" | "investigative" | "coordinated" Express tracks (express_auto/express_assist) are gated per-organization: they require the org to have Express Claims enabled, otherwise an explicit express value is rejected with 400 express_not_enabled. When omitted, the organization's configured default is used if valid and allowed; otherwise the request defaults to investigative.
delivery "auto" | "return_link" auto sends the link; return_link skips delivery and returns the magic link only.
metadata object Echoed back in the response and ignored by processing.

Responses: 200 Idempotent replay of a previous create. · 201 Inspection created. · 400 Bad request — body validation failed, no destination for the chosen channel, or an express handlingTrack was requested for an org that does not have Express Claims enabled. · 401 · 403 · 404 · 409 Conflict — a claim with the supplied claimNumber already exists, or another request with this Idempotency-Key is still processing. · 422 · 429 · 500 · 503

GET /inspections/{id}

Get inspection status and results

Scope: inspections:read

Parameters
Name Type Description
id required path · string (uuid)

Responses: 200 Current status and results. · 401 · 404 · 429 · 500 · 503

GET /inspections/{id}/report

Get the structured submitted report (JSON)

Returns the structured report for a submitted, administrator-released inspection: claim/claimant, visible answers, severity, photo count, sufficiency review, walkaround validation, weather, and photo-location verification. Includes links to the PDF and photo endpoints. Returns `403 report_not_released` until the report is released.

Scope: inspections:read

Parameters
Name Type Description
id required path · string (uuid)

Responses: 200 The structured report. · 401 · 403 · 404 · 429 · 500 · 503

GET /inspections/{id}/report.pdf

Download the report as a PDF

Streams an administrator-released PDF rendering of the report (with embedded photos) as an attachment. Returns `403 report_not_released` before release and 404 if the inspection does not exist for this organization.

Scope: inspections:read

Parameters
Name Type Description
id required path · string (uuid)

Responses: 200 PDF document. · 401 · 403 · 404 · 429 · 500 · 503

GET /inspections/{id}/photos

List inspection photos with signed URLs

Returns each captured photo with a short-lived signed download URL (~1 hour), step metadata, per-photo AI analysis, and capture geolocation.

Scope: inspections:read

Parameters
Name Type Description
id required path · string (uuid)

Responses: 200 Photo list. · 401 · 404 · 429 · 500 · 503

GET /inspections/{id}/photos.zip

Download all photos as a ZIP bundle

Streams a ZIP of all photos for the inspection (including submitted supplements) as an attachment.

Scope: inspections:read

Parameters
Name Type Description
id required path · string (uuid)

Responses: 200 ZIP archive. · 401 · 404 · 429 · 500 · 503

GET /templates

List the calling org's inspection templates

Lists the inspection templates belonging to the organization the API key is scoped to. Use the returned `id` values as `templateId` when triggering an inspection.

Scope: inspections:read

Parameters
Name Type Description
category query · "property" | "vehicle" Filter to a category. Use vehicle for new work; property remains available for legacy template reads.
active query · boolean Filter by active state.

Responses: 200 List of templates for the organization. · 401 · 422 · 429 · 503

Webhooks

Add an endpoint in Settings → API & Webhooks. Each endpoint gets a signing secret, shown once. Deliveries are POST requests with these headers:

  • X-CIQ-Event: the event name
  • X-CIQ-Delivery: a unique delivery ID. Deduplicate on it.
  • X-CIQ-Signature: t=<unix-seconds>,v1=<hmac-hex>
{
  "event": "inspection.submitted",
  "id": "<delivery id, equals X-CIQ-Delivery>",
  "created_at": "2026-06-01T19:12:13.570Z",
  "data": {
    "entityType": "inspection_request",
    "entityId": "<inspection request id>",
    "eventType": "inspection_submitted"
  }
}
Webhook events
inspection.created An inspection request was created from the dashboard or the API.
inspection.opened The recipient opened the inspection.
inspection.submitted The inspection was submitted. Includes report and photo URLs.
inspection.analyzed AI analysis finished.
inspection.sufficiency_completed The sufficiency review finished.
inspection.supplement_created A follow-up photo request was created.
inspection.triage.completed An Express triage result was produced.
turnaround.completed A fleet condition check was submitted, with its verdict.

Verify every delivery

The signature is an HMAC-SHA256 of ${t}.${rawBody} using your endpoint's secret. Verify against the raw body bytes, use a constant-time comparison, and reject timestamps older than about five minutes.

import crypto from "node:crypto";

// Mount with a raw body parser so you verify the exact signed bytes:
//   app.post("/ciq-webhook", express.raw({ type: "application/json" }), handler)
function verifyCiqWebhook(req, secret, toleranceSec = 300) {
  const header = req.get("X-CIQ-Signature") || "";
  const parts = Object.fromEntries(header.split(",").map((kv) => kv.split("=")));
  const t = Number(parts.t);
  const sig = parts.v1;
  if (!t || !sig) return false;
  if (Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${req.body}`)
    .digest("hex");
  const a = Buffer.from(sig);
  const b = Buffer.from(expected);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
  • At-least-once delivery. Failed deliveries retry with increasing delays (1m, 5m, 30m, 2h, 6h; up to six attempts).
  • Ordering isn't guaranteed. Reconcile with the status endpoint when order matters.
  • Acknowledge quickly. A non-2xx response or a reply slower than 10 seconds counts as a failure.

MCP server

The Model Context Protocol server exposes the API as tools for AI agents and assistants over Streamable HTTP at https://inspection360.ai/api/mcp. It uses the same API keys and scopes, and every tool calls the matching REST endpoint, so validation and idempotency behave identically.

{
  "mcpServers": {
    "complete-iq": {
      "url": "https://inspection360.ai/api/mcp",
      "headers": { "Authorization": "Bearer ciq_sk_live_..." }
    }
  }
}
MCP tools
Tool Scope Endpoint
list_templates inspections:read GET /templates
create_inspection inspections:write POST /inspections
get_inspection inspections:read GET /inspections/{id}
get_inspection_report inspections:read GET /inspections/{id}/report
list_inspection_photos inspections:read GET /inspections/{id}/photos

The PDF report and photo ZIP are binary, so agents use the URLs returned by the inspection and photo tools.

Errors and rate limits

Errors use one envelope: { "error": { "code", "message" } }. Requests are limited to 120 per minute per client IP; beyond that you'll get HTTP 429, so retry with backoff.

Error codes
HTTP Code Meaning
400 invalid_request The body failed validation. The message names the field.
400 missing_destination No phone or email for the chosen delivery channel.
400 express_not_enabled An Express track was requested but Express isn't enabled for your organization.
401 missing_api_key No API key was sent.
401 invalid_api_key The key wasn't found or was revoked.
403 insufficient_scope The key lacks the required scope.
403 report_not_released The report exists but hasn't been released by an administrator.
404 not_found The inspection wasn't found in your organization.
404 template_not_found The templateId wasn't found in your organization.
409 request_in_flight A request with the same Idempotency-Key is still processing. Retry shortly.
409 claim_number_exists A claim with that claimNumber already exists.
422 no_template No active template for the loss type. Pass templateId or create one.
503 auth_unavailable Authentication is temporarily unavailable. Retry.

Questions about the API? Email support@completeiq.com.

Planning an integration?

We'll walk through the API, webhooks and how inspections fit your claims workflow.

Choose which optional cookies we may use. Your choice is saved in this browser.