API wey dey use OCR read water meter
API wey dey use OCR read water meter. This page explain the public HTTP API wey website backend open for outside system to connect.
Start with real picture upload
Create account first, upload your own water meter picture for work area, then create API key when you ready to connect your system.
Quick overview
- Use website backend for every outside connection.
- Outside program no suppose call waterMeterAi direct.
- Open API dey share the same user, quota, cache, task and audit rule with website portal.
- Backend fit target different AI service according to deployment setting.
- Task response get general result_summary object so different service fit show different kind of result.
How to prove who you be
- Log in for website and create API key for API Keys page.
- Complete API key go show only one time when dem create am.
- Send the key inside Authorization header for every request.
Authorization: Bearer wm_xxxxxxxxxxxxxxxxx
API Key Permissions and Limits
- Each API key can have independent scopes, an IPv4/IPv6/CIDR allowlist, a total requests-per-minute limit, and a task submissions-per-minute limit.
- A valid key without the required scope or outside its source IP allowlist returns 403.
- Every valid-key request consumes the total request limit, including requests rejected by scope, IP, or submission policy.
- Batch requests consume one total request unit and one submission unit per uploaded file.
- Rate-limited responses return 429 with Retry-After and both X-RateLimit-* and X-SubmissionLimit-* headers.
- Task creation also has a per-key concurrency limit and returns X-ConcurrencyLimit-* headers; a concurrency rejection uses 429.
- For batch concurrency, only files that pass image validation reserve slots, and success headers report the actual active slots after task binding.
Retry-After: 30 X-RateLimit-Limit: 60 X-RateLimit-Remaining: 59 X-RateLimit-Reset: 1785902400 X-SubmissionLimit-Limit: 10 X-SubmissionLimit-Remaining: 9 X-ConcurrencyLimit-Limit: 3 X-ConcurrencyLimit-Active: 1 X-ConcurrencyLimit-Remaining: 2
Rule for picture upload
- Highest file size na 20MB for each picture.
- The format dem wey e support na JPEG, PNG and WEBP.
- Backend dey check the real file content, no be only file extension.
How backend dey enforce upload size
- By default, batch upload fit collect up to 8 picture, with 20MB limit for each picture and 20MB total limit for all file content.
- If one file or full batch pass the limit, backend go return 413 before picture check or task creation; e no go create half batch.
- Backend dey enforce the byte wey e receive, even if Content-Length no dey or request use chunked transfer.
Meaning of task status
- queued: system don collect the task and e dey wait for AI processing.
- running: system dey process am now, or e don hand am to dispatcher and still dey check final result.
- batch_waiting_ai: every item for the batch dey wait make AI service come back online; work never start.
- batch_running: system don hand the batch to dispatcher and processing still dey go on.
- done: task finish well.
- failed: processing fail.
- waiting_ai: task dey queue until AI service come back online, then e go continue by itself.
Where result come from
- fresh: new AI run produce the result.
- cached_exact: picture match cache for current AI version.
- cached_stale: AI dey offline, so backend return the latest old cache result.
- pending: final result never dey yet.
- failed: the task fail.
- If task never finish, check error_message for the latest reason why e retry or wait.
Quota and payment
- Use `GET /api/open/quota` before you send plenty work if your connection need avoid quota failure.
- Na only new AI run with `fresh` source dey use quota.
- Result with `cached_exact`, `cached_stale`, `pending` or `failed` no dey use quota.
- Free account dey use daily quota first. Paid account dey use active periodic quota package, then temporary or fixed quota according to backend policy.
- When quota finish, task submission go return `429` with error message instead of creating new task.
Cache and how current result be
- Backend dey cache successful result with picture hash, AI version and downstream service namespace.
- `cached_exact` mean say the same picture get successful result for current AI version already, so new AI run no dey needed.
- `cached_stale` mean say AI service dey offline and backend return the latest historical result wey dey available.
- When `is_latest_ai_version` na false, keep the result as historical data wey person fit use but suppose review.
- No assume say every `done` task use quota; check `result_source`.
Task completion webhooks
- Send signed task completion events to your HTTPS endpoint with automatic retries.
- This API key is inactive. Existing records remain available, but new, enabled, test, and secret-rotation operations are blocked.
X-WaterMeter-Webhook-Id: whev_new_event X-WaterMeter-Webhook-Replay-Of: whev_original_event replay_of_event_id: whev_original_event blocked endpoint management: HTTP 409 canceled delivery status: canceled
GET/api/open/quota
/api/open/quotaGet current quota and the amount wey remain.
Example of request
curl -X GET "https://watermeterai.com/api/open/quota" \ -H "Authorization: Bearer wm_xxxxxxxxxxxxxxxxx"
Example of response
{
"ok": true,
"email": "[email protected]",
"quota": {
"account_type": "free",
"daily_limit": 20,
"used": 3,
"remaining": 17,
"day_tag": "2026-06-01",
"is_unlimited": false,
"monthly_remaining": 0,
"monthly_bonus_remaining": 0,
"fixed_remaining": 0,
"nearest_expire_at": null,
"quota_summary_text": "Free daily quota: 3/20 used today. Remaining: 17."
}
}GET/api/open/ai-status
/api/open/ai-statusGet public service status for task submission and cache-result fallback.
Example of request
curl -X GET "https://watermeterai.com/api/open/ai-status" \ -H "Authorization: Bearer wm_xxxxxxxxxxxxxxxxx"
Example of response
{
"ok": true,
"is_online": true,
"busy": false,
"active_jobs": 0,
"public_status": "online",
"public_status_label": "online",
"public_status_reason": "ready",
"accepts_new_tasks": true,
"can_return_cached_result": true,
"queue_state": "idle",
"queue_count": 0,
"current_ai_version": "water_v2:wm-ai-v2-2026-06-01",
"last_checked_at": "2026-06-01T06:15:30Z"
}POST/api/open/tasks
/api/open/tasksUpload one picture and create one task.
Example of request
curl -X POST "https://watermeterai.com/api/open/tasks" \ -H "Authorization: Bearer wm_xxxxxxxxxxxxxxxxx" \ -F "file=@D:\data\meter_001.jpg"
Example of response
{
"ok": true,
"task_id": "8e6c4d1f8f8348c0bc53e2e39d2dc111",
"status": "queued",
"result_source": "pending",
"visibility": "private",
"ai_online": true,
"is_latest_ai_version": false,
"final_reading": "-",
"result_summary": {
"resultKind": "unknown",
"primaryLabel": "Result",
"primaryValue": "-",
"secondaryLabel": "Detail",
"secondaryValue": "-",
"summaryText": "No result is available yet."
},
"error_message": "",
"created_at": "2026-06-01T06:16:10Z"
}GET/api/open/tasks/{task_id}
/api/open/tasks/{task_id}Get one task status and final reading.
Example of request
curl -X GET "https://watermeterai.com/api/open/tasks/task_a" \ -H "Authorization: Bearer wm_xxxxxxxxxxxxxxxxx"
Example of response
{
"ok": true,
"task_id": "8e6c4d1f8f8348c0bc53e2e39d2dc111",
"status": "done",
"result_source": "fresh",
"ai_online": true,
"is_latest_ai_version": true,
"final_reading": "123.45",
"meter_type": "pointer",
"success": "yes",
"result_summary": {
"resultKind": "water_meter",
"primaryLabel": "Final Reading",
"primaryValue": "123.45",
"secondaryLabel": "Meter Type",
"secondaryValue": "pointer",
"summaryText": "Water meter recognition finished."
},
"error_message": "",
"created_at": "2026-06-01T06:16:10Z"
}GET/api/open/tasks
/api/open/tasksGet recent task wey belong to the user of current API key.
Example of request
curl -X GET "https://watermeterai.com/api/open/tasks?limit=20" \ -H "Authorization: Bearer wm_xxxxxxxxxxxxxxxxx"
Example of response
{
"ok": true,
"items": [
{
"task_id": "8e6c4d1f8f8348c0bc53e2e39d2dc111",
"status": "done",
"result_source": "cached_exact",
"final_reading": "123.45",
"meter_type": "pointer",
"success": "yes",
"result_summary": {},
"ai_online": true,
"is_latest_ai_version": true,
"created_at": "2026-06-01T06:16:10Z",
"error_message": ""
}
]
}POST/api/open/batches
/api/open/batchesUpload many picture inside one request.
Example of request
curl -X POST "https://watermeterai.com/api/open/batches" \ -H "Authorization: Bearer wm_xxxxxxxxxxxxxxxxx" \ -F "files=@D:\data\meter_001.jpg" \ -F "files=@D:\data\meter_002.jpg"
Example of response
{
"ok": true,
"batch_id": "5a14f4e5f6d34fdabce00e62c0dd0001",
"status": "batch_running",
"total_count": 2,
"done_count": 0,
"failed_count": 0,
"pending_count": 2,
"items": [
{
"index": 0,
"file_name": "meter_001.jpg",
"task_id": "task_a",
"status": "queued",
"result_source": "pending",
"final_reading": "-",
"failure_kind": "",
"error_message": ""
},
{
"index": 1,
"file_name": "meter_002.jpg",
"task_id": "task_b",
"status": "queued",
"result_source": "pending",
"final_reading": "-",
"failure_kind": "",
"error_message": ""
}
]
}GET/api/open/batches/{batch_id}
/api/open/batches/{batch_id}Get batch progress and task status for each file.
Example of request
curl -X GET "https://watermeterai.com/api/open/batches/5a14f4e5f6d34fdabce00e62c0dd0001" \ -H "Authorization: Bearer wm_xxxxxxxxxxxxxxxxx"
Example of response
{
"ok": true,
"batch_id": "5a14f4e5f6d34fdabce00e62c0dd0001",
"status": "batch_done",
"total_count": 2,
"done_count": 2,
"failed_count": 0,
"pending_count": 0,
"items": [
{
"index": 0,
"file_name": "meter_001.jpg",
"task_id": "task_a",
"status": "done",
"result_source": "fresh",
"final_reading": "123.45",
"failure_kind": "",
"error_message": ""
},
{
"index": 1,
"file_name": "meter_002.jpg",
"task_id": "task_b",
"status": "done",
"result_source": "cached_exact",
"final_reading": "456.78",
"failure_kind": "",
"error_message": ""
}
]
}Process wey we recommend
- Check `GET /api/open/ai-status` before you send plenty work.
- Keep `task_id` or `batch_id` for your own system immediately after submission.
- Treat `queued`, `running`, `waiting_ai`, `batch_waiting_ai` and `batch_running` as status wey never finish, and continue to check status.
- Use batch request when network road to backend slow and the service wey dem deploy support batch mode.
- Batch request dey pass through `webBackend -> dispatchCenter -> waterMeterAi` now.
- `batch_waiting_ai` mean say every item still dey wait for AI service and work never start.
- When the service wey dem deploy na `CAD`, use `POST /api/open/tasks` for now and treat batch upload as something wey no dey available.
Information about error
- 400: request no correct, or deployed service no support batch upload.
- 401: API key no dey, e no correct, e don expire or dem disable am.
- 403: the user account is not active, the key lacks the required scope, or the source IP is outside the key allowlist.
- 404: task or batch no dey, or e no belong to current user.
- 413: file too big.
- 415: picture type no dey supported or picture content no correct.
- 429: quota exhausted or the API key request, submission, or concurrency limit was exceeded.
400 batch upload no dey available
{
"detail": "batch upload is not supported for business: cax"
}401 API key no dey or e no correct
{
"ok": false,
"error": "unauthorized",
"message": "Missing or invalid API key."
}413 file too big
{
"ok": false,
"error": "file_too_large",
"message": "Maximum file size is 20MB."
}429 quota don finish
{
"ok": false,
"error": "quota_exhausted",
"message": "Quota exhausted.",
"quota": {
"remaining": 0,
"quota_summary_text": "Free daily quota: 20/20 used today. Remaining: 0."
}
}You ready to test the full process?
Use website work area for the first picture, then move to API key when the result format match your system.