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.
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:
{
"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:
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.
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
- API reference: Verify — every request parameter, response field, and error code.
- Authentication — key format, header, and rotation.
- Concepts: Categories — how to interpret
the
categoryandis_compliantfields you get back.