WaterMeter AI

水表 OCR API

水表 OCR API. 本页说明网站后端对外开放的 HTTP API,供第三方系统接入。

先从真实上传开始

先注册账号,在工作台上传你自己的水表照片;确认结果格式适合后,再创建 API Key 接入系统。

总览

  • 所有外部集成都应调用网站后端。
  • 第三方程序不要直接调用 waterMeterAi。
  • 开放 API 与网站共用用户、额度、缓存、任务和审计规则。
  • 后端可根据部署配置切换不同下游 AI 业务。
  • 任务返回中已包含通用 result_summary,便于不同业务展示不同结果类型。

鉴权

  • 先登录网站,然后在 API 密钥页创建 API key。
  • 完整 API key 只会在创建时显示一次。
  • 每个请求都要在 Authorization 头中带上该 key。
Authorization: Bearer wm_xxxxxxxxxxxxxxxxx

API Key 权限与限制

  • 每个 API Key 可独立配置 Scope、IPv4/IPv6/CIDR 白名单、总请求分钟限额和任务提交分钟限额。
  • 有效 Key 缺少目标 Scope,或来源 IP 不在白名单时返回 403。
  • 每个已通过 Key 鉴权的请求都会计入总请求限额,包括被 Scope、IP 或提交策略拒绝的请求。
  • 批量请求按一次总请求计算,并按上传文件数累计提交单位。
  • 触发限速时返回 429、Retry-After,以及 X-RateLimit-* 和 X-SubmissionLimit-* 两组响应头。
  • 任务创建还受单 Key 并发上限约束,并返回 X-ConcurrencyLimit-* 响应头;并发不足时返回 429。
  • 批量并发只为通过图片校验的文件预留槽位,成功响应头反映任务绑定后的实际活动槽。
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

上传规则

  • 单张图片最大 20MB。
  • 支持格式:JPEG、PNG、WEBP。
  • 后端会校验真实文件内容,而不是只看扩展名。

上传大小限制

  • 批量上传默认最多接收 8 张图片,单张上限为 20MB,全部文件内容合计上限为 20MB。
  • 单个文件或整批超过限制时,后端会在图片校验或创建任务之前返回 413,且不会创建部分批次。
  • 即使请求缺少 Content-Length 或使用分块传输,后端仍会按实际接收的字节数执行限制。

任务状态

  • queued:已接收,等待 AI 处理。
  • running:AI 正在处理,或已交给收发室但仍在轮询最终结果。
  • batch_waiting_ai:整批里的每一项都还在等待 AI 恢复,尚未真正开始执行。
  • batch_running:整批任务已交给收发室,仍在处理中。
  • done:成功完成。
  • failed:处理失败。
  • waiting_ai:AI 离线,先排队等待恢复;恢复后会自动继续。

结果来源

  • fresh:本次新跑 AI 得到。
  • cached_exact:命中当前 AI 版本缓存。
  • cached_stale:AI 离线时,返回最新历史缓存。
  • pending:最终结果尚未生成。
  • failed:任务失败。
  • 任务未完成时,可结合 error_message 查看最近一次等待或重试原因。

额度与计费

  • 如果你的接入需要避免额度不足导致失败,提交大量任务前先调用 `GET /api/open/quota`。
  • 只有 `fresh` AI 新识别会消耗额度。
  • `cached_exact`、`cached_stale`、`pending` 和 `failed` 结果不消耗额度。
  • 免费账号优先使用每日额度。付费账号按后端策略优先使用有效周期额度包,再使用临时额度或固定额度。
  • 额度耗尽时,提交任务会返回 `429` 和错误信息,不会创建新任务。

缓存与结果新鲜度

  • 后端按图片 hash 和 AI 版本缓存成功结果,并包含下游业务命名空间。
  • `cached_exact` 表示同一图片在当前 AI 版本下已有成功结果,因此不需要再次运行 AI。
  • `cached_stale` 表示 AI 服务离线,后端返回了当前可用的最新历史结果。
  • 当 `is_latest_ai_version` 为 false 时,应把结果当作可用但需要复核的历史数据保存。
  • 不要假设每个 `done` 任务都消耗了额度;应检查 `result_source`。

任务完成 Webhook

  • 任务完成后向你的 HTTPS 地址发送签名事件,并在失败时自动重试。
  • 此 API Key 已失效。仍可查看记录或停用、删除端点,但不能新建、启用、测试或轮换签名密钥。
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

读取当前额度和剩余额度。

请求示例
curl -X GET "https://watermeterai.com/api/open/quota" \
  -H "Authorization: Bearer wm_xxxxxxxxxxxxxxxxx"
响应示例
{
  "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

读取可公开展示的服务状态,用于判断是否可提交任务以及是否可回退缓存结果。

请求示例
curl -X GET "https://watermeterai.com/api/open/ai-status" \
  -H "Authorization: Bearer wm_xxxxxxxxxxxxxxxxx"
响应示例
{
  "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

上传一张图片并创建单任务。

请求示例
curl -X POST "https://watermeterai.com/api/open/tasks" \
  -H "Authorization: Bearer wm_xxxxxxxxxxxxxxxxx" \
  -F "file=@D:\data\meter_001.jpg"
响应示例
{
  "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}

读取单个任务状态和最终读数。

请求示例
curl -X GET "https://watermeterai.com/api/open/tasks/task_a" \
  -H "Authorization: Bearer wm_xxxxxxxxxxxxxxxxx"
响应示例
{
  "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 Key 用户名下的最近任务。

请求示例
curl -X GET "https://watermeterai.com/api/open/tasks?limit=20" \
  -H "Authorization: Bearer wm_xxxxxxxxxxxxxxxxx"
响应示例
{
  "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

一次请求上传多张图片。

请求示例
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"
响应示例
{
  "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}

读取批次进度和每张图片的任务状态。

请求示例
curl -X GET "https://watermeterai.com/api/open/batches/5a14f4e5f6d34fdabce00e62c0dd0001" \
  -H "Authorization: Bearer wm_xxxxxxxxxxxxxxxxx"
响应示例
{
  "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": ""
    }
  ]
}

推荐调用流程

  • 批量发送前先检查 `GET /api/open/ai-status`。
  • 提交后立刻在你的系统里保存 `task_id` 或 `batch_id`。
  • 把 `queued`、`running`、`waiting_ai`、`batch_waiting_ai`、`batch_running` 都视为未结束状态并持续轮询。
  • 如果网站后端网络延时较高,且部署业务支持批量模式,优先用批量接口。
  • 当前批量链路是 `webBackend -> dispatchCenter -> waterMeterAi`。
  • `batch_waiting_ai` 表示整批都还在等 AI,不代表已经开始跑。
  • 当部署业务是 `CAD` 时,暂时只用 `POST /api/open/tasks`,把批量能力视为不可用。

错误说明

  • 400:请求无效,或当前部署业务不支持批量上传。
  • 401:API key 缺失、无效、过期或被禁用。
  • 403:用户账户不可用、Key 缺少目标 Scope,或来源 IP 不在 Key 白名单中。
  • 404:任务或批次不存在,或不属于当前用户。
  • 413:文件过大。
  • 415:图片类型不支持或图片内容无效。
  • 429:额度已用完,或 API Key 的请求、提交、并发任务上限已触发。
400:批量上传不可用
{
  "detail": "batch upload is not supported for business: cax"
}
401:API key 缺失或无效
{
  "ok": false,
  "error": "unauthorized",
  "message": "Missing or invalid API key."
}
413:文件过大
{
  "ok": false,
  "error": "file_too_large",
  "message": "Maximum file size is 20MB."
}
429:额度已用完
{
  "ok": false,
  "error": "quota_exhausted",
  "message": "Quota exhausted.",
  "quota": {
    "remaining": 0,
    "quota_summary_text": "Free daily quota: 20/20 used today. Remaining: 0."
  }
}

准备测试完整流程?

先用网页工作台跑第一张图片,确认读数和结果结构后,再进入 API Key 接入。