AI services
Integrate license plate recognition
Send a photo of a vehicle and get back a normalised plate number with vehicle type, registration region and confidence. Tuned for Vietnamese plates.
Choose an endpoint
| Endpoint | Use when |
|---|---|
POST /v1/ai/license-plates/recognize | The photo shows the whole vehicle. The plate is located for you. |
POST /v1/ai/license-plates/recognize-cropped | The image is already cropped to the plate. Skips detection, so it is faster. |
Request
Send multipart/form-data:
- file is required. JPEG, PNG, WebP, GIF, BMP or TIFF, up to 10 MB.
- image_base64 is an alternative to file: raw Base64, or a data:image/...;base64 URL. Send filename alongside it if you want a name in the result.
Examples
curl -X POST https://core.roammoon.com/v1/ai/license-plates/recognize \
-H "X-API-Key: rm_live_YOUR_KEY" \
-F "file=@motorbike.jpg"Response
Returns a plates array, most confident first:
{
"country": "Vietnam",
"filename": "motorbike.jpg",
"plates": [
{
"is_valid": true,
"best_raw": "47-AB\n123.45",
"best_normalized": "47AB12345",
"vehicle": "motorcycle",
"type": "Private organization / individual",
"region_code": "47",
"region_name": "Dak Lak",
"current_administrative_region": "Dak Lak",
"era": "current",
"layout": "double",
"background": "white",
"votes": 3,
"confidence": 0.9,
"validation_reason": null
}
],
"processing_time_ms": 142.517
}The plates array is empty. If OCR read a string that does not match Vietnamese plate rules, the string is still returned with is_valid = false, so you decide whether to use it.
Fields that matter
| Field | Meaning |
|---|---|
best_normalized | Letters and digits only, no separators. Use this for matching and storage. |
best_raw | Keeps the dots, dashes and line breaks as they appear on the plate. Use this for display. |
is_valid | Whether the result matches Vietnamese plate rules. |
confidence, votes | votes is how many OCR passes agreed on this reading. More votes with high confidence is more trustworthy. |
region_code, current_administrative_region | The registering province code and today's administrative unit, which differ where provinces have merged. |
Billing
One credit is charged only when recognition succeeds and the result is returned. Every failure is refunded, whether the image was rejected or the service itself could not complete the request.
The charge policy is charge-on-success: credit is reserved when the request is accepted and only committed once processing succeeds. A failure refunds the reservation.
Getting good accuracy
- Sharp images where the plate fills a meaningful part of the frame. Motion blur is the most common cause of misreads.
- If you already know where the plate is, recognize-cropped is faster and less noisy.
- Always check is_valid before writing to your database rather than trusting the string outright.
Errors
Every error uses the same shape. Branch on code, not on message, because messages can change.
{
"error": {
"code": "IMAGE_TOO_LARGE",
"message": "The uploaded image is too large."
}
}| HTTP | Code | What to do |
|---|---|---|
| 401 | API_KEY_REQUIRED | The X-API-Key header is missing. |
| 401 | API_KEY_INVALID | The key is wrong, disabled or expired. Check it or create a new one. |
| 403 | API_KEY_FORBIDDEN | The key is not permitted to use this service. |
| 400 | INVALID_LICENSE_PLATE_REQUEST | The image or options are invalid. No credit is charged. |
| 402 | CREDIT_LIMIT_EXCEEDED | The period's credits are exhausted. Upgrade or wait for the next period. |
| 413 | IMAGE_TOO_LARGE | The image exceeds 10 MB. Compress or resize it. |
| 415 | UNSUPPORTED_IMAGE_TYPE | The image format is not supported. |
| 429 | RATE_LIMIT_EXCEEDED | Per-minute request limit exceeded. Slow down. |
| 429 | LICENSE_PLATE_SERVICE_BUSY | The service is saturated. Retry after a few seconds. |
| 502 | LICENSE_PLATE_UPSTREAM_ERROR | The model could not complete the request. Retryable. |
| 503 | LICENSE_PLATE_SERVICE_UNAVAILABLE | The service is temporarily unavailable. Retryable. |
Retrying safely
429, 502 and 503 are retryable, so use exponential backoff. Other errors return the same result on retry. Only a successful recognition is charged, so retrying after a failure costs nothing extra. The exception is a network timeout: if the first attempt actually succeeded, the retry is charged as a second call.