Documentation
The VisionPlate REST API recognizes Iraqi license plates in vehicle photos. For the full, interactive schema, see the API reference.
Getting started
Create an account, buy credits and create an API key in your account. Every request needs the key in the X-Api-Key header. Keys look like vp_live_… and are shown only once when created, so store yours securely and keep it on the server side, not in browser code. Send the image as multipart/form-data.
curl -X POST https://your-domain/api/v1/recognize \
-H "X-Api-Key: vp_live_your_key" \
-F "image=@car.jpg"Recognize a plate
POST /api/v1/recognize takes a single file field named image (JPEG, PNG, WebP or BMP). Add ?includeCrop=true to also receive the cropped plate as a base64 PNG. When no plate is found, the request still succeeds with "detected": false and uses one credit.
{
"success": true,
"data": {
"id": "0199a0c4-6f1e-7c2b-9d3a-5b8f1e2d4c6a",
"detected": true,
"plateNumber": "12 A 34567",
"province": "baghdad",
"provinceCode": 1,
"vehicleType": "private",
"vehicleCode": 1,
"plateType": "New",
"boundingBox": { "x": 412, "y": 530, "width": 220, "height": 64 },
"fileName": "car.jpg",
"processingMs": 84.3,
"createdAtUtc": "2026-09-30T10:15:00Z",
"croppedPlatePng": null
},
"error": null,
"meta": null
}Response fields
| Field | Description |
|---|---|
| id | Unique ID of this recognition in your history. |
| detected | false when no plate was found in the image. |
| plateNumber | Recognized plate text. |
| province / provinceCode | Governorate name and numeric code, when readable. |
| vehicleType / vehicleCode | Vehicle category (e.g. private, public, cargo) and numeric code. |
| plateType | Plate design: Kurdistan (old), Nineties, Germany or New. |
| boundingBox | Plate location in the original image, in pixels. |
| processingMs | Processing time for this image. |
| croppedPlatePng | Base64 PNG of the plate. Only returned with includeCrop=true. |
Batch recognition
POST /api/v1/recognize/batch accepts up to 10 files, each in a field named images. Each item in the response has its own success flag. Files that fail validation return an error for that item only and use no credits.
curl -X POST https://your-domain/api/v1/recognize/batch \
-H "X-Api-Key: vp_live_your_key" \
-F "images=@car1.jpg" \
-F "images=@car2.jpg"History
GET /api/v1/recognitions returns your key's past recognitions, newest first. You can filter with plate (partial match), from and to (ISO-8601 UTC), and page with page and pageSize (max 100). Paging info is returned in meta. Fetch a single entry with GET /api/v1/recognitions/{id}.
curl "https://your-domain/api/v1/recognitions?page=1&pageSize=20&plate=12345" \
-H "X-Api-Key: vp_live_your_key"Usage & limits
Requests are paid from your account's prepaid credits: each image recognized uses one credit, and all your keys share the balance. Buy credit packages in your account. GET /api/v1/usage shows your balance and this key's usage this month, and recognition responses include an X-Credits-Remaining header. Each key also has a per-minute rate limit (429 rate_limited with a Retry-After header). With no credits left you get 402 insufficient_credits.
Errors
Every error uses the same envelope. Use the code field in your code; the message is for humans and may change.
{
"success": false,
"data": null,
"error": { "code": "insufficient_credits", "message": "Not enough credits for this request..." },
"meta": null
}| Status | Code | Meaning |
|---|---|---|
| 400 | missing_image | No file was sent in the expected field. |
| 400 | invalid_image | The file isn't a readable image. |
| 400 | unsupported_format | Use JPEG, PNG, WebP or BMP. |
| 400 | image_too_large | File size or pixel count is over the limit. |
| 400 | batch_too_large | More files than the batch limit. |
| 401 | unauthorized | Missing, unknown or revoked API key. |
| 404 | not_found | The resource doesn't exist or isn't yours. |
| 429 | rate_limited | Per-minute limit hit; check Retry-After. |
| 402 | insufficient_credits | No credits left; buy a package. |
| 500 | server_error | Unexpected failure. Safe to retry. |
Code examples
using var http = new HttpClient { BaseAddress = new Uri("https://your-domain/") };
http.DefaultRequestHeaders.Add("X-Api-Key", "vp_live_your_key");
using var form = new MultipartFormDataContent();
var file = new ByteArrayContent(await File.ReadAllBytesAsync("car.jpg"));
file.Headers.ContentType = new("image/jpeg");
form.Add(file, "image", "car.jpg");
var response = await http.PostAsync("api/v1/recognize", form);
var json = await response.Content.ReadAsStringAsync();
Console.WriteLine(json);const form = new FormData();
form.append("image", fileInput.files[0]);
const res = await fetch("https://your-domain/api/v1/recognize", {
method: "POST",
headers: { "X-Api-Key": "vp_live_your_key" },
body: form,
});
const { success, data, error } = await res.json();
console.log(success ? data.plateNumber : error.message);