REST (curl)

VerifyAI is a plain HTTP/JSON API. You don't need an official SDK — anything that can make a POST request works. This page shows the raw calls with curl plus a few language snippets, so you can integrate from Go, Ruby, PHP, or anywhere else.

When to use an SDK instead

If you're on React Native or Flutter and want a drop-in camera scanner with the capture / upload / retry loop handled for you, use the React Native or Flutter SDK. The REST API is the right choice for server-side calls and any language without an official SDK.

The essentials

| | | | --------------- | ------------------------------------------------------ | | Base URL | https://verify.switchlabs.dev/api | | Auth | X-API-Key: vai_… header on every request | | Content | multipart/form-data or application/json | | Image limit | 10 MB, JPEG / PNG / WebP |

See Authentication for key format and rotation.

Verify a photo (multipart)

Multipart is the simplest way to send a file from a shell or server. Two fields are required: image and policy.

curl -X POST https://verify.switchlabs.dev/api/v1/verify \
-H "X-API-Key: vai_your_api_key" \
-F "image=@scooter.jpg" \
-F "policy=scooter_parking"

Verify a photo (JSON + base64)

If sending a file is awkward — say you already hold the image as a base64 string — POST JSON instead. The image field accepts a raw base64 string or a full data URL; the data:image/...;base64, prefix is stripped automatically.

curl -X POST https://verify.switchlabs.dev/api/v1/verify \
-H "X-API-Key: vai_your_api_key" \
-H "Content-Type: application/json" \
-d '{
  "image": "data:image/jpeg;base64,/9j/4AAQ...",
  "policy": "scooter_parking",
  "metadata": { "device_id": "dev_123" }
}'

The response

A 200 OK is a verification object. The fields you'll branch on:

json
{
  "id": "ver_8x92m4k9",
  "status": "success",
  "is_compliant": false,
  "confidence": 0.94,
  "policy": "scooter_parking",
  "category": "unsafe",
  "violation_reasons": ["blocking_sidewalk", "kickstand_up"],
  "feedback": "Please deploy the kickstand and move away from the walkway.",
  "image_url": "https://...signed-url..."
}

See Your first verification for a field-by-field walkthrough and the full Verify endpoint reference for every parameter.

Idempotency

Network drops and client retries happen. Send an Idempotency-Key header and a retry with the same key returns the original cached response instead of re-running (and re-billing) the verification:

bash
curl -X POST https://verify.switchlabs.dev/api/v1/verify \
  -H "X-API-Key: vai_your_api_key" \
  -H "Idempotency-Key: 9c7f1c44-1d0e-4ea1-9f55-2c2a39d7fcb1" \
  -F "image=@scooter.jpg" -F "policy=scooter_parking"

Keys are scoped per route. Reusing a key with a different request body returns 422 Unprocessable Entity.

Handling errors and rate limits

Errors return a non-200 status and an error string. Build retry logic around the status code:

| Status | Action | | ------ | ---------------------------------------------------------------------------- | | 400 | Fix the request — missing field, image too large, or unknown policy ID. | | 401 | Check the X-API-Key header. | | 403 | Key isn't valid for VerifyAI, or no active subscription. | | 429 | Back off — read the Retry-After header (seconds) and retry after it. | | 5xx | Transient — retry with backoff, reusing your Idempotency-Key. |

Every response carries an X-Request-Id header. Log it; it's the fastest way for support to trace a specific call.

bash
curl -i -X POST https://verify.switchlabs.dev/api/v1/verify \
  -H "X-API-Key: vai_your_api_key" \
  -F "image=@scooter.jpg" -F "policy=scooter_parking" \
  | grep -iE "x-request-id|server-timing"

What's next

Get in Touch

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