返回首页

DocWise.ai API 与 MCP 服务器

最后更新:2026-11-01

DocWise.ai API 让你在自己的代码里翻译文档,质量档位、价格和限制都与网页版相同。远程 MCP 服务器把同样的能力提供给 AI 智能体(Claude、Cursor 及其他 MCP 客户端)。

API 属于 Pro 和 Ultra 方案。机器可读的规范:/api/v1/openapi.json(OpenAPI 3.1)。

快速开始

  1. 在 Pro 或 Ultra 方案下打开 API 密钥 并创建一个密钥。密钥以 sk_ 开头,只显示一次:请立即保存到你的密钥管理处。
  2. 上传、翻译、下载:
export DOCWISE_KEY=sk_...
API=https://docwise.ai/api/v1

# 1. Declare the file: you get a presigned upload URL
curl -s -X POST $API/documents \
  -H "Authorization: Bearer $DOCWISE_KEY" -H "Content-Type: application/json" \
  -d '{"filename":"report.pdf","bytes":'$(wc -c < report.pdf)',"mime":"application/pdf"}'
# → {"document":{"id":"DOC_ID",...},"method":"PUT","url":"https://…","expires_in":3600}

# 2. Upload the bytes straight to storage (curl sets Content-Length)
curl -s -X PUT -T report.pdf "UPLOAD_URL"

# 3. Finish: the file is read and priced
curl -s -X POST $API/documents/DOC_ID/complete -H "Authorization: Bearer $DOCWISE_KEY"
# → {"document":{...,"pages":12},"quote":{"pages":12,"tiers":[{"tier":"standard","credits":24,...}],...}}

# 4. Translate (credits are held now, settled when the job ends)
curl -s -X POST $API/translations \
  -H "Authorization: Bearer $DOCWISE_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: report-de-2026-11-01" \
  -d '{"document_id":"DOC_ID","tgt_lang":"de","tier":"standard"}'
# → {"id":"JOB_ID","status":"queued","billing":{"held_credits":24,...},...}

# 5. Poll until done, then get download links (valid 5 minutes)
curl -s $API/translations/JOB_ID -H "Authorization: Bearer $DOCWISE_KEY"
curl -s $API/translations/JOB_ID/outputs -H "Authorization: Bearer $DOCWISE_KEY"

认证

每个请求都带上密钥:Authorization: Bearer sk_...。密钥属于你的账户,只能看到你自己的文档和翻译;别人的 id 一律返回 404。请从服务器调用 API,不要在网页里调用:API 不发送 CORS 头,也从不接受 Cookie。

翻译流程

  1. POST /documents,传 filename、精确字节数 bytes 和 mime。支持的格式和大小限制与网页版相同(GET /formats)。16 MiB 以内返回一个 url;更大的文件返回 parts,按顺序分别上传到各自的 URL,每段 part_size 字节(最后一段较短)。
  2. 在 expires_in 秒(1 小时)内用完全相同的 Content-Length PUT 上传字节。链接过期了?调用 POST /documents/{id}/upload-urls。
  3. POST /documents/{id}/complete 读取文档并返回 { document, quote }。quote.tiers[] 列出每个档位的积分价格,以及在你的方案中是否 available。之后可用 GET /documents/{id}/quote 重新报价。
  4. POST /translations,传 document_id、tgt_lang(取自 GET /languages)、tier,可选 glossary_id、src_lang、outputs 和 trial: true(只翻译前 3 页;之后对同一文档、语言和档位做完整翻译时,这几页不再收费)。
  5. 每 2–5 秒轮询 GET /translations/{id}。status 依次为 queued → parsing → translating → reviewing → rendering → done(或 failed、canceled);progress 从 0 到 1。
  6. GET /translations/{id}/outputs 为每个输出文件返回一个预签名链接,有效期 5 分钟;GET /translations/{id}/zip 把全部文件打包成一个 ZIP 流式返回。

POST /translations/{id}/cancel 取消任务;DELETE /documents/{id} 立即删除文件及所有输出(进行中的任务会被取消并退款)。

积分与档位

1 积分 = 快速档 1 页。一页是一页 PDF 或一张幻灯片,或 2,000 个字符的文本。

创建翻译时冻结 页数 × 每页积分。任务结束时按实际交付扣费,绝不超过冻结额;失败或取消的任务全额退回。每个翻译的 billing 显示 held_credits、charged_credits 和 refunded_credits。

幂等

调用 POST /translations 时发送 Idempotency-Key: <8–128 个字母、数字或 . _ : ->。24 小时内用同一个键、同样的请求体重试,会返回同一个翻译(响应头 Idempotency-Replayed: true),绝不会重复冻结积分。同一个键配不同的请求体返回 409 idempotency_conflict。失败的请求没有任何效果,可以用同一个键重试。

限制

错误

所有错误都是带真实 HTTP 状态码的 JSON:

{ "error": { "code": "insufficient_credits", "message": "Not enough credits" } }

Python

import os, time, requests

API = "https://docwise.ai/api/v1"
H = {"Authorization": f"Bearer {os.environ['DOCWISE_KEY']}"}

def call(method, path, **kw):
    while True:
        r = requests.request(method, API + path, headers={**H, **kw.pop("headers", {})}, **kw)
        if r.status_code != 429:
            break
        time.sleep(int(r.headers.get("Retry-After", "1")))
    if r.status_code >= 400:
        raise RuntimeError(r.json()["error"])
    return r.json()

data = open("report.pdf", "rb").read()
up = call("POST", "/documents", json={"filename": "report.pdf", "bytes": len(data), "mime": "application/pdf"})
requests.put(up["url"], data=data).raise_for_status()  # files ≤ 16 MiB: one PUT
doc = call("POST", f"/documents/{up['document']['id']}/complete")
print("pages:", doc["quote"]["pages"])

job = call("POST", "/translations", json={"document_id": doc["document"]["id"], "tgt_lang": "de", "tier": "standard"},
           headers={"Idempotency-Key": f"report-de-{doc['document']['id']}"})
while job["status"] not in ("done", "failed", "canceled"):
    time.sleep(3)
    job = call("GET", f"/translations/{job['id']}")

for out in call("GET", f"/translations/{job['id']}/outputs")["outputs"]:
    open(out["filename"], "wb").write(requests.get(out["url"]).content)

JavaScript(Node 18+)

import { readFile, writeFile } from 'node:fs/promises';

const API = 'https://docwise.ai/api/v1';
const H = { Authorization: `Bearer ${process.env.DOCWISE_KEY}` };
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

async function call(method, path, body, headers = {}) {
  for (;;) {
    const res = await fetch(API + path, {
      method,
      headers: { ...H, ...headers, ...(body ? { 'Content-Type': 'application/json' } : {}) },
      body: body ? JSON.stringify(body) : undefined,
    });
    if (res.status === 429) { await sleep(1000 * Number(res.headers.get('retry-after') || 1)); continue; }
    const json = await res.json();
    if (!res.ok) throw new Error(`${json.error.code}: ${json.error.message}`);
    return json;
  }
}

const bytes = await readFile('report.pdf');
const up = await call('POST', '/documents', { filename: 'report.pdf', bytes: bytes.length, mime: 'application/pdf' });
await fetch(up.url, { method: 'PUT', body: bytes });
const { document, quote } = await call('POST', `/documents/${up.document.id}/complete`);
console.log('credits on Balanced:', quote.tiers.find((t) => t.tier === 'standard').credits);

let job = await call('POST', '/translations', { document_id: document.id, tgt_lang: 'de', tier: 'standard' },
  { 'Idempotency-Key': `report-de-${document.id}` });
while (!['done', 'failed', 'canceled'].includes(job.status)) {
  await sleep(3000);
  job = await call('GET', `/translations/${job.id}`);
}
const { outputs } = await call('GET', `/translations/${job.id}/outputs`);
for (const out of outputs)
  await writeFile(out.filename, Buffer.from(await (await fetch(out.url)).arrayBuffer()));

MCP 服务器

端点:https://docwise.ai/api/mcp(Streamable HTTP),用同一个 API 密钥作为 Bearer 令牌。工具:get_account、list_languages、list_documents、upload_document、complete_upload、quote_document、translate_document、get_translation、get_download_links、cancel_translation、list_glossaries。

upload_document 接受最大 10 MB 的 base64 文件内容;更大的文件会返回预签名上传链接,由你的客户端 PUT 上传,再调用 complete_upload。服务器从不抓取你提供的 URL。智能体会被要求在 translate_document 之前先和你确认积分花费。

Claude Code

claude mcp add --transport http docwise https://docwise.ai/api/mcp \
  --header "Authorization: Bearer sk_..."

Cursor(~/.cursor/mcp.json,或项目里的 .cursor/mcp.json)

{
  "mcpServers": {
    "docwise": {
      "url": "https://docwise.ai/api/mcp",
      "headers": { "Authorization": "Bearer sk_..." }
    }
  }
}

Claude Desktop(设置 → 开发者 → 编辑配置,claude_desktop_config.json;通过 mcp-remote 桥接,需要 Node.js)

{
  "mcpServers": {
    "docwise": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://docwise.ai/api/mcp", "--header", "Authorization:${DOCWISE_AUTH}"],
      "env": { "DOCWISE_AUTH": "Bearer sk_..." }
    }
  }
}

不要把密钥提交到共享仓库:优先使用环境变量或客户端自带的密钥存储。