本页内容
文件上传 API
POST https://api.meowload.net/openapi/v1/uploads 为音频、图片和视频提供同一套上传流程,返回 uploadId,需要传文件时还会返回单次 PUT 地址。
申请使用 Authorization: Bearer <你的 API Key>。API 积分余额须大于 0,但申请上传不扣积分;业务任务独立检查余额和计费,单价见 开发者管理中心 的「计费规则」。
使用流程
- 计算原文件的精确字节数和 SHA-256,POST
/uploads申请上传。 upload非空时,将完整原始文件 PUT 到返回地址,原样携带全部返回请求头,不附加哼哼猫 API Key。等待 PUT 返回成功的 2xx。upload为 null 时,表示已命中本用户可复用的已验证内容,跳过 PUT。- 将
uploadId直接交给支持的业务任务。音视频转文字 使用mediaType: "audio"申请,随后 POST/transcriptions,提交{uploadId, language?, speakerLabels?}。
不提供公开 complete、上传状态 GET、分片、地址续签、文件列表或删除端点。服务端在任务后台确认上传并校验文件,验证失败通过该业务任务交付。
音频、图片、视频共用申请接口,但业务仍会核对实际媒体类型。当前转录只接收音频 uploadId,本指南不表示图片/视频任务 API 已经开放。
大小与格式
mediaType | 接收范围 |
|---|---|
audio | 可解码音频,最多 1 GiB(1,073,741,824 字节) |
image | JPEG、PNG、WebP,最多 30 MiB(31,457,280 字节)、1 亿像素 |
video | MP4,最多 500 MiB(524,288,000 字节)、600 秒 |
声明、文件名和 Content-Type 不决定真实格式,仍会验证文件内容、大小、摘要与元数据。文件验证通过,也不代表任意业务或模型都能接收。
M4A/MP4 容器可只包含音频;音频的附带封面不视为真实视频轨道。含真实视频轨的文件不能通过声明 audio 来转录,应先提取音轨再上传,或使用转录的音视频文件直链输入。
申请上传
curl https://api.meowload.net/openapi/v1/uploads \
-H 'Authorization: Bearer <你的 API Key>' \
-H 'Content-Type: application/json' \
-d '{"mediaType":"audio","fileName":"meeting.mp3","sizeBytes":12345678,"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"}'示例大小和摘要仅用于说明,需按实际文件计算。
| 字段 | 必填 | 规则 |
|---|---|---|
mediaType | 是 | audio、image 或 video |
fileName | 否 | 展示用文件名,不作为格式校验依据 |
sizeBytes | 是 | 原文件精确字节数,正整数,须符合所选类型的限制 |
sha256 | 是 | 完整原文件的 SHA-256,64 位十六进制字符 |
申请 JSON 正文最多 8 KiB,不包含文件正文,也不接受存储路径、模型、价格、内部素材 ID 或调用方指定的请求 ID。上传申请没有公开幂等参数。
响应与 PUT
HTTP 200:
{
"uploadId": "0123456789abcdefghijklmn",
"upload": {
"method": "PUT",
"url": "https://uploads.example.com/signed-object?signature=EXAMPLE",
"headers": {"Content-Type":"application/octet-stream"},
"expiresAt": "2030-01-01T01:00:00.000Z"
}
}使用完整返回地址和全部返回请求头,包括可能存在的校验头。上面的 headers 是示例,不是固定请求头清单。发送文件原始字节,不使用 multipart 表单:
curl --request PUT '<upload.url>' \
--header 'Content-Type: application/octet-stream' \
--header '<其他返回请求头>: <原值>' \
--data-binary @meeting.mp3PUT 地址最长有效 1 小时,同时受当前上传会话剩余时间约束。upload.expiresAt 是本次签名地址的期限,不是已验证文件的可用期限。中断后在地址有效期内重传同一个完整文件,不支持分片续传;地址过期则重新申请,不往原地址发送不同内容。
PUT 成功只表示文件送达,不表示通过真实媒体验证。收到 2xx 后直接创建业务任务,不需要解析 ETag、调用 complete 或轮询上传状态。
已验证内容复用响应:
{"uploadId":"0123456789abcdefghijklmn","upload":null}只有明确的 null 才表示可跳过 PUT,并不表示业务任务已经完成。
多任务复用与期限
同一有效 uploadId 可以创建多个参数不同的任务,前提是属于本用户、源文件当前可用且符合对应业务的媒体规则。同用户轮换 Key 后仍可引用,他人的 Key 不可使用。
每次业务 POST 创建独立任务,可能分别收费,即使引用同一 uploadId。文件身份不是任务幂等键;创建回包丢失时不要自动重试任务 POST。拿到任务 ID 后保存它,只重试免费的结果 GET。
不额外设置“uploadId 创建满 24 小时便禁止新任务”的规则。原上传会话与来源当前使用资格仍然有效,uploadId 不保证永久保存;源文件不再可用时可重新申请上传。已经保存的转录文字不依赖原文件保留,仍可查询。
Node.js:流式计算摘要并上传
Node.js 24 可使用文件支持的 Blob,示例不会把 1 GiB 文件整体放进内存。摘要计算至 PUT 期间不要修改文件。示例仅创建一次转录,后续按 转录指南 每 3 秒查询。
import { createHash } from "node:crypto"
import { createReadStream, openAsBlob } from "node:fs"
const base = "https://api.meowload.net/openapi/v1"
const auth = { Authorization: "Bearer <你的 API Key>", "Content-Type": "application/json" }
const path = "./meeting.mp3"
const file = await openAsBlob(path)
const hash = createHash("sha256")
for await (const chunk of createReadStream(path)) hash.update(chunk)
const application = await fetch(`${base}/uploads`, {
method: "POST",
headers: auth,
body: JSON.stringify({ mediaType: "audio", fileName: "meeting.mp3", sizeBytes: file.size, sha256: hash.digest("hex") }),
})
if (!application.ok) throw new Error(`Upload request failed: ${application.status}`)
const { uploadId, upload } = await application.json()
if (upload !== null) {
const put = await fetch(upload.url, { method: upload.method, headers: upload.headers, body: file })
if (!put.ok) throw new Error(`PUT failed: ${put.status}`)
}
const created = await fetch(`${base}/transcriptions`, {
method: "POST", headers: auth,
body: JSON.stringify({ uploadId, language: "auto", speakerLabels: false }),
})
if (!created.ok) throw new Error(`Create failed: ${created.status}`)
console.log("Save this task ID:", (await created.json()).id)API 请求错误沿用非 2xx 与 {message, code?, detail?}。文件真实校验失败通过业务任务返回,发生在执行预扣之前。完整参数与返回字段见 API 参考。