DEVELOPERS / OPENAPI v1

让你的应用,
认出每一只猫。

猫谱猫脸识别 API 接入指南

从第一张注册图片,到一次猫咪个体检索。通过标准 HTTP 接口建立猫谱、管理任务和获取身份候选结果。

公开文档 · 阅读无需登录

首次调用前

  1. 在开放平台控制台登录并创建项目,复制完整的项目 UUID。
  2. 为项目创建 API Key,配置所需权限,并保存只显示一次的密钥。
  3. 创建猫咪个体,保存返回的 id,再上传注册图片。
  4. 查询任务列表,确认注册完成后上传查询图片,获得相似度排序结果。
示例中的 {{base_url}}是你的 HTTPS API 服务地址, {{api_key}} 是项目密钥。请从平台部署配置或服务提供方获取 API 地址;官网地址用于阅读文档,不承接 /v1 业务请求。

cURL 示例使用 Bash 续行语法。Windows 用户可在 Postman 中通过 Import → Raw text 导入,设置 base_url 和 api_key,并重新选择上传图片。Python 示例在服务端运行,需安装 requests 并设置环境变量。

AUTHENTICATION

一个项目,一组访问凭证

业务接口接受 Authorization: Bearer mk_live_… ,也接受拥有该项目的用户登录 Token。每个 Key 绑定一个项目,能够访问其权限范围内的项目数据。

Scope 允许操作
cats:read读取个体、注册图片列表和图片内容
cats:write管理个体、注册图片、设置主图和选择注册候选猫
recognition:write执行猫咪身份识别查询
tasks:read读取任务状态、结果、统计和预览图片

Key 的启停、吊销、有效期和 IP 白名单都会参与鉴权。完整访问包含以上四项权限;创建 Key 时空 scopes 数组会授予全部四项。重试任务接口目前接受 cats:write 或 recognition:write 任一权限。

项目创建与设置、API Key 管理、钱包、账单和用量查询需要用户登录 Token,不能用 API Key 调用。请将密钥保存在服务端环境变量中。

WORKFLOW

注册是异步的,识别等待结果

上传注册图片返回 HTTP 202 和 task_id。此时 vectors_added 为 0 属于正常情况,后台完成特征提取后,图片才参与检索。识别请求优先排队,并等待推理完成后返回结果。

queued → running → completed
                 → waiting_user → selection → queued
                 → failed → retry → queued

每隔几秒调用 GET /tasks?limit=10&offset=0 ,在列表中按 id 查找 task_id。当前没有 GET /tasks/ {task_id} 单独详情接口。任务按创建时间倒序排列;翻页使用 offset,并按任务 ID 去重。

注册图片检测到多只猫时,任务可能进入 waiting_user。查看候选图片后,通过 selection 提交 candidate_index;也可以 cancel 放弃本次待选择注册。只有 failed 状态的任务可以 retry。

请求超时不等于任务失败。先查任务列表,避免重复上传产生额外调用和费用。当前接口没有通用 Idempotency-Key 去重保证。

LIMITS & ERRORS

限流、计费与错误处理

默认每 Key 每秒允许识别 2 次、注册及写操作 10 次、读取 20 次,部署配置可以调整。遇到 429 请按 Retry-After 等待重试。常规成功 JSON 响应可查看 X-RateLimit-Limit 和 X-RateLimit-Remaining。

图片默认上限 15 MiB,可配置;支持 JPEG、PNG、WebP。注册与识别按猫咪向量提取计费,价格和赠送额度以控制台为准。错误响应 detail 可能是字符串、结构化对象或校验数组,请保留 HTTP 状态码和 X-Request-Id。

HTTP 错误码 / detail 说明
401invalid_api_keyKey 格式错误、密钥不匹配或不存在
401expired_api_keyKey 已过期
403api_key_disabled / api_key_revokedKey 已禁用或吊销
403project_mismatchKey 不属于此项目
403scope_denied缺少接口所需权限
403ip_not_allowed来源 IP 不在白名单
404Not found项目、个体、图片或任务不存在
409Conflict任务当前状态不允许此操作
413Image is too large图片超过上传大小限制
415Unsupported media type仅支持 JPEG、PNG、WebP
422Validation error检查字段类型、必填项和范围
429rate_limit_exceeded降低并发,按 Retry-After 等待后重试
503Recognition task failed推理不可用,检查任务状态后决定是否重试

API REFERENCE / v1

创建个体

POST/v1/projects/{project_id}/cats

所需权限: cats:write。同时支持拥有该项目的用户登录 Token。将路径中的占位符替换为实际 ID。

name 为 1–100 字符,创建时必填; metadata 为 JSON 对象; active 默认为 true。修改时只提交需要更新的字段。

cURL / Postman

curl --request POST '{{base_url}}/v1/projects/{project_id}/cats' \
  --header 'Authorization: Bearer {{api_key}}' \
  --header 'Content-Type: application/json' \
  --data '{"name":"Mimi","metadata":{},"active":true}'
查看 Python 示例
import os
import json
import requests

api_key = os.environ["MEOWID_API_KEY"]
base_url = os.environ["MEOWID_API_BASE"].rstrip("/")
# 将 {project_id}、{cat_id} 等占位符替换为实际 ID。
response = requests.post(
    base_url + "/v1/projects/{project_id}/cats",
    headers={"Authorization": f"Bearer {api_key}"},
    json=json.loads("{\"name\":\"Mimi\",\"metadata\":{},\"active\":true}"),
    timeout=120,
)
response.raise_for_status()
print(response.content)

API REFERENCE / v1

个体列表

GET/v1/projects/{project_id}/cats

所需权限: cats:read。同时支持拥有该项目的用户登录 Token。将路径中的占位符替换为实际 ID。

cURL / Postman

curl --request GET '{{base_url}}/v1/projects/{project_id}/cats' \
  --header 'Authorization: Bearer {{api_key}}'
查看 Python 示例
import os
import requests

api_key = os.environ["MEOWID_API_KEY"]
base_url = os.environ["MEOWID_API_BASE"].rstrip("/")
# 将 {project_id}、{cat_id} 等占位符替换为实际 ID。
response = requests.get(
    base_url + "/v1/projects/{project_id}/cats",
    headers={"Authorization": f"Bearer {api_key}"},
    timeout=120,
)
response.raise_for_status()
print(response.content)

API REFERENCE / v1

修改个体

PATCH/v1/projects/{project_id}/cats/{cat_id}

所需权限: cats:write。同时支持拥有该项目的用户登录 Token。将路径中的占位符替换为实际 ID。

name 为 1–100 字符,创建时必填; metadata 为 JSON 对象; active 默认为 true。修改时只提交需要更新的字段。

cURL / Postman

curl --request PATCH '{{base_url}}/v1/projects/{project_id}/cats/{cat_id}' \
  --header 'Authorization: Bearer {{api_key}}' \
  --header 'Content-Type: application/json' \
  --data '{"name":"Mimi","active":true}'
查看 Python 示例
import os
import json
import requests

api_key = os.environ["MEOWID_API_KEY"]
base_url = os.environ["MEOWID_API_BASE"].rstrip("/")
# 将 {project_id}、{cat_id} 等占位符替换为实际 ID。
response = requests.patch(
    base_url + "/v1/projects/{project_id}/cats/{cat_id}",
    headers={"Authorization": f"Bearer {api_key}"},
    json=json.loads("{\"name\":\"Mimi\",\"active\":true}"),
    timeout=120,
)
response.raise_for_status()
print(response.content)

API REFERENCE / v1

删除个体

DELETE/v1/projects/{project_id}/cats/{cat_id}

所需权限: cats:write。同时支持拥有该项目的用户登录 Token。将路径中的占位符替换为实际 ID。

删除个体同时清理其图片和向量;删除图片会移除对应向量。删除个体成功返回 204,无响应体。

cURL / Postman

curl --request DELETE '{{base_url}}/v1/projects/{project_id}/cats/{cat_id}' \
  --header 'Authorization: Bearer {{api_key}}'
查看 Python 示例
import os
import requests

api_key = os.environ["MEOWID_API_KEY"]
base_url = os.environ["MEOWID_API_BASE"].rstrip("/")
# 将 {project_id}、{cat_id} 等占位符替换为实际 ID。
response = requests.delete(
    base_url + "/v1/projects/{project_id}/cats/{cat_id}",
    headers={"Authorization": f"Bearer {api_key}"},
    timeout=120,
)
response.raise_for_status()
print(response.content)

API REFERENCE / v1

上传注册图片

POST/v1/projects/{project_id}/cats/{cat_id}/images

所需权限: cats:write。同时支持拥有该项目的用户登录 Token。将路径中的占位符替换为实际 ID。

请求体使用 multipart/form-data,必填字段 image 为图片文件。每次上传一张 JPEG、PNG 或 WebP;让客户端自动设置 Content-Type 和 boundary。

成功返回 202 queued 和 task_id,通过任务列表跟踪注册进度。

cURL / Postman

curl --request POST '{{base_url}}/v1/projects/{project_id}/cats/{cat_id}/images' \
  --header 'Authorization: Bearer {{api_key}}' \
  --form 'image=@cat.jpg;type=image/jpeg'
查看 Python 示例
import os
import requests

api_key = os.environ["MEOWID_API_KEY"]
base_url = os.environ["MEOWID_API_BASE"].rstrip("/")
# 将 {project_id}、{cat_id} 等占位符替换为实际 ID。
with open("cat.jpg", "rb") as image:
    response = requests.post(
        base_url + "/v1/projects/{project_id}/cats/{cat_id}/images",
        headers={"Authorization": f"Bearer {api_key}"},
        files={"image": ("cat.jpg", image, "image/jpeg")},
        timeout=120,
    )
response.raise_for_status()
print(response.content)

API REFERENCE / v1

注册图片列表

GET/v1/projects/{project_id}/cats/{cat_id}/images

所需权限: cats:read。同时支持拥有该项目的用户登录 Token。将路径中的占位符替换为实际 ID。

cURL / Postman

curl --request GET '{{base_url}}/v1/projects/{project_id}/cats/{cat_id}/images' \
  --header 'Authorization: Bearer {{api_key}}'
查看 Python 示例
import os
import requests

api_key = os.environ["MEOWID_API_KEY"]
base_url = os.environ["MEOWID_API_BASE"].rstrip("/")
# 将 {project_id}、{cat_id} 等占位符替换为实际 ID。
response = requests.get(
    base_url + "/v1/projects/{project_id}/cats/{cat_id}/images",
    headers={"Authorization": f"Bearer {api_key}"},
    timeout=120,
)
response.raise_for_status()
print(response.content)

API REFERENCE / v1

获取图片文件

GET/v1/projects/{project_id}/cats/{cat_id}/images/{image_id}/content

所需权限: cats:read。同时支持拥有该项目的用户登录 Token。将路径中的占位符替换为实际 ID。

成功响应为图片二进制内容,不是 JSON。

cURL / Postman

curl --request GET '{{base_url}}/v1/projects/{project_id}/cats/{cat_id}/images/{image_id}/content' \
  --header 'Authorization: Bearer {{api_key}}'
查看 Python 示例
import os
import requests

api_key = os.environ["MEOWID_API_KEY"]
base_url = os.environ["MEOWID_API_BASE"].rstrip("/")
# 将 {project_id}、{cat_id} 等占位符替换为实际 ID。
response = requests.get(
    base_url + "/v1/projects/{project_id}/cats/{cat_id}/images/{image_id}/content",
    headers={"Authorization": f"Bearer {api_key}"},
    timeout=120,
)
response.raise_for_status()
print(response.content)

API REFERENCE / v1

设置主图

PATCH/v1/projects/{project_id}/cats/{cat_id}/images/{image_id}/primary

所需权限: cats:write。同时支持拥有该项目的用户登录 Token。将路径中的占位符替换为实际 ID。

cURL / Postman

curl --request PATCH '{{base_url}}/v1/projects/{project_id}/cats/{cat_id}/images/{image_id}/primary' \
  --header 'Authorization: Bearer {{api_key}}'
查看 Python 示例
import os
import requests

api_key = os.environ["MEOWID_API_KEY"]
base_url = os.environ["MEOWID_API_BASE"].rstrip("/")
# 将 {project_id}、{cat_id} 等占位符替换为实际 ID。
response = requests.patch(
    base_url + "/v1/projects/{project_id}/cats/{cat_id}/images/{image_id}/primary",
    headers={"Authorization": f"Bearer {api_key}"},
    timeout=120,
)
response.raise_for_status()
print(response.content)

API REFERENCE / v1

删除图片

DELETE/v1/projects/{project_id}/cats/{cat_id}/images/{image_id}

所需权限: cats:write。同时支持拥有该项目的用户登录 Token。将路径中的占位符替换为实际 ID。

删除个体同时清理其图片和向量;删除图片会移除对应向量。删除个体成功返回 204,无响应体。

cURL / Postman

curl --request DELETE '{{base_url}}/v1/projects/{project_id}/cats/{cat_id}/images/{image_id}' \
  --header 'Authorization: Bearer {{api_key}}'
查看 Python 示例
import os
import requests

api_key = os.environ["MEOWID_API_KEY"]
base_url = os.environ["MEOWID_API_BASE"].rstrip("/")
# 将 {project_id}、{cat_id} 等占位符替换为实际 ID。
response = requests.delete(
    base_url + "/v1/projects/{project_id}/cats/{cat_id}/images/{image_id}",
    headers={"Authorization": f"Bearer {api_key}"},
    timeout=120,
)
response.raise_for_status()
print(response.content)

API REFERENCE / v1

任务列表与结果

GET/v1/projects/{project_id}/tasks

所需权限: tasks:read。同时支持拥有该项目的用户登录 Token。将路径中的占位符替换为实际 ID。

limit 范围 1–200,默认 100; offset ≥ 0,默认 0。返回数组包含任务状态和 result。

cURL / Postman

curl --request GET '{{base_url}}/v1/projects/{project_id}/tasks?limit=10&offset=0' \
  --header 'Authorization: Bearer {{api_key}}'
查看 Python 示例
import os
import requests

api_key = os.environ["MEOWID_API_KEY"]
base_url = os.environ["MEOWID_API_BASE"].rstrip("/")
# 将 {project_id}、{cat_id} 等占位符替换为实际 ID。
response = requests.get(
    base_url + "/v1/projects/{project_id}/tasks?limit=10&offset=0",
    headers={"Authorization": f"Bearer {api_key}"},
    timeout=120,
)
response.raise_for_status()
print(response.content)

API REFERENCE / v1

任务统计

GET/v1/projects/{project_id}/tasks/summary

所需权限: tasks:read。同时支持拥有该项目的用户登录 Token。将路径中的占位符替换为实际 ID。

cURL / Postman

curl --request GET '{{base_url}}/v1/projects/{project_id}/tasks/summary' \
  --header 'Authorization: Bearer {{api_key}}'
查看 Python 示例
import os
import requests

api_key = os.environ["MEOWID_API_KEY"]
base_url = os.environ["MEOWID_API_BASE"].rstrip("/")
# 将 {project_id}、{cat_id} 等占位符替换为实际 ID。
response = requests.get(
    base_url + "/v1/projects/{project_id}/tasks/summary",
    headers={"Authorization": f"Bearer {api_key}"},
    timeout=120,
)
response.raise_for_status()
print(response.content)

API REFERENCE / v1

查询原图

GET/v1/projects/{project_id}/tasks/{task_id}/query

所需权限: tasks:read。同时支持拥有该项目的用户登录 Token。将路径中的占位符替换为实际 ID。

成功响应为图片二进制内容,不是 JSON。

cURL / Postman

curl --request GET '{{base_url}}/v1/projects/{project_id}/tasks/{task_id}/query' \
  --header 'Authorization: Bearer {{api_key}}'
查看 Python 示例
import os
import requests

api_key = os.environ["MEOWID_API_KEY"]
base_url = os.environ["MEOWID_API_BASE"].rstrip("/")
# 将 {project_id}、{cat_id} 等占位符替换为实际 ID。
response = requests.get(
    base_url + "/v1/projects/{project_id}/tasks/{task_id}/query",
    headers={"Authorization": f"Bearer {api_key}"},
    timeout=120,
)
response.raise_for_status()
print(response.content)

API REFERENCE / v1

候选猫图片

GET/v1/projects/{project_id}/tasks/{task_id}/candidates/{candidate_index}

所需权限: tasks:read。同时支持拥有该项目的用户登录 Token。将路径中的占位符替换为实际 ID。

成功响应为图片二进制内容,不是 JSON。

cURL / Postman

curl --request GET '{{base_url}}/v1/projects/{project_id}/tasks/{task_id}/candidates/{candidate_index}' \
  --header 'Authorization: Bearer {{api_key}}'
查看 Python 示例
import os
import requests

api_key = os.environ["MEOWID_API_KEY"]
base_url = os.environ["MEOWID_API_BASE"].rstrip("/")
# 将 {project_id}、{cat_id} 等占位符替换为实际 ID。
response = requests.get(
    base_url + "/v1/projects/{project_id}/tasks/{task_id}/candidates/{candidate_index}",
    headers={"Authorization": f"Bearer {api_key}"},
    timeout=120,
)
response.raise_for_status()
print(response.content)

API REFERENCE / v1

选择注册候选猫

POST/v1/projects/{project_id}/tasks/{task_id}/selection

所需权限: cats:write。同时支持拥有该项目的用户登录 Token。将路径中的占位符替换为实际 ID。

仅适用于 waiting_user 状态的注册任务,其他状态返回 409。candidate_index 为非负整数。

cURL / Postman

curl --request POST '{{base_url}}/v1/projects/{project_id}/tasks/{task_id}/selection' \
  --header 'Authorization: Bearer {{api_key}}' \
  --header 'Content-Type: application/json' \
  --data '{"candidate_index":0}'
查看 Python 示例
import os
import json
import requests

api_key = os.environ["MEOWID_API_KEY"]
base_url = os.environ["MEOWID_API_BASE"].rstrip("/")
# 将 {project_id}、{cat_id} 等占位符替换为实际 ID。
response = requests.post(
    base_url + "/v1/projects/{project_id}/tasks/{task_id}/selection",
    headers={"Authorization": f"Bearer {api_key}"},
    json=json.loads("{\"candidate_index\":0}"),
    timeout=120,
)
response.raise_for_status()
print(response.content)

API REFERENCE / v1

放弃待选择注册

POST/v1/projects/{project_id}/tasks/{task_id}/cancel

所需权限: cats:write。同时支持拥有该项目的用户登录 Token。将路径中的占位符替换为实际 ID。

仅适用于 waiting_user 状态的注册任务,其他状态返回 409。candidate_index 为非负整数。

cURL / Postman

curl --request POST '{{base_url}}/v1/projects/{project_id}/tasks/{task_id}/cancel' \
  --header 'Authorization: Bearer {{api_key}}'
查看 Python 示例
import os
import requests

api_key = os.environ["MEOWID_API_KEY"]
base_url = os.environ["MEOWID_API_BASE"].rstrip("/")
# 将 {project_id}、{cat_id} 等占位符替换为实际 ID。
response = requests.post(
    base_url + "/v1/projects/{project_id}/tasks/{task_id}/cancel",
    headers={"Authorization": f"Bearer {api_key}"},
    timeout=120,
)
response.raise_for_status()
print(response.content)

API REFERENCE / v1

重试失败任务

POST/v1/projects/{project_id}/tasks/{task_id}/retry

所需权限: cats:write / recognition:write。同时支持拥有该项目的用户登录 Token。将路径中的占位符替换为实际 ID。

只有 failed 状态且保留了源数据的任务可重试,成功返回 202。

cURL / Postman

curl --request POST '{{base_url}}/v1/projects/{project_id}/tasks/{task_id}/retry' \
  --header 'Authorization: Bearer {{api_key}}'
查看 Python 示例
import os
import requests

api_key = os.environ["MEOWID_API_KEY"]
base_url = os.environ["MEOWID_API_BASE"].rstrip("/")
# 将 {project_id}、{cat_id} 等占位符替换为实际 ID。
response = requests.post(
    base_url + "/v1/projects/{project_id}/tasks/{task_id}/retry",
    headers={"Authorization": f"Bearer {api_key}"},
    timeout=120,
)
response.raise_for_status()
print(response.content)

接口路径、请求体与权限信息同步自平台现有开发者文档。示例仅含占位符,不包含可用密钥。