上傳一個包含 Markdown 與本地圖片的 ZIP 壓縮檔,建立非同步匯入任務。系統會自動處理資源、修復引用路徑,並在任務完成後產出可供預覽、發布及後續工作流程使用的 HTML。
專為 markdown2html 工作流程打造,不是通用的 API 文件頁
專為 Obsidian 與 Markdown 套件匯出(含相對圖片引用)所設計,並透過任務佇列穩定處理匯入。
建立任務並輪詢狀態後,即可取得可直接預覽、發布或交付後續流程的 HTML,無需額外手動清理。
確保品牌內容、知識庫發布與批次工作流程中的輸出樣式保持一致。
文章與資源保持整潔有序,讓搜尋、重複使用與團隊協作更易於管理。
先將來自 Obsidian、知識庫或本地編輯檔案的 Markdown 文章打包成 ZIP 並上傳。
再建立非同步匯入任務,讓系統自動處理圖片上傳、引用路徑替換與版面轉換。
輪詢任務完成後,將產出的結果導入發布、分發、AI 增強或內部編輯流程中。
下方區塊同時作為開發者控制台與 AI / 工程團隊可直接使用的非同步整合文件。
一鍵建立 API 金鑰,並可直接複製下方 Markdown 指南給 AI 代理或工程團隊依照非同步流程接入。
建立匯入 API 金鑰
權杖僅在建立後顯示一次。若遺失,請撤銷並重新建立。
現有金鑰
尚無 API 金鑰
主題 API 識別碼
每個 themeId 皆對應編輯器中顯示的主題名稱。人類可讀名稱與參考顏色列於下方。
AI 可讀的 API 整合指南
公众号https://api.imgto.link
POST https://api.imgto.link/uploads/md-importPOST https://api.imgto.link/api/v1/md/importGET https://api.imgto.link/api/v1/md/import/jobs/{jobId}https://api.imgto.link host, so clients only need one public base URL.Use an API key in the Authorization header:
Authorization: Bearer YOUR_API_KEY
uploadRelativePathPOST https://api.imgto.link/api/v1/md/importGET https://api.imgto.link/api/v1/md/import/jobs/{jobId} until the job reaches a terminal statusPOST https://api.imgto.link/uploads/md-import
multipart/form-data
archive (required): ZIP file containing one Markdown file and its local image files{
"code": 200,
"data": {
"relativePath": "inbox/2026/03/12/uuid-article-package.zip",
"originalFilename": "article-package.zip",
"size": 345678,
"uploadedAt": "2026-03-12T08:00:00.000Z"
}
}
POST https://api.imgto.link/api/v1/md/import
application/json
{
"uploadRelativePath": "inbox/2026/03/12/uuid-article-package.zip",
"archiveFilename": "article-package.zip",
"archiveSize": 345678,
"themeId": "classic",
"directoryPath": "public/articles/demo",
"entryMarkdown": "docs/index.md",
"saveFolderId": 12,
"mdfileId": 123
}
uploadRelativePath (required): value returned from step 1archiveFilename (required): original zip filenamearchiveSize (optional): archive size in bytesthemeId (optional): theme API name, default is classicdirectoryPath (optional): base upload directory path like public/articles/launch-2026entryMarkdown (optional): specific markdown file path inside the ZIP when there are multiple markdown filessaveFolderId (optional): target markdown folder ID in the editormdfileId (optional): existing markdown article ID. When provided, the import is treated as a replace/update. The old article and its imported images are deleted before the new content is saved{
"code": 202,
"message": "Accepted",
"data": {
"jobId": "mdi_1234567890abcdef",
"status": "QUEUED",
"progress": 0,
"pollUrl": "/api/v1/md/import/jobs/mdi_1234567890abcdef"
}
}
GET https://api.imgto.link/api/v1/md/import/jobs/{jobId}
{
"code": 200,
"message": "Ok",
"data": {
"jobId": "mdi_1234567890abcdef",
"status": "PROCESSING",
"progress": 65,
"currentStage": "processing_images",
"message": "正在处理图片 2/4",
"compensationStatus": "NOT_REQUIRED",
"updatedAt": "2026-03-12T08:01:15.000Z"
}
}
{
"code": 200,
"message": "Ok",
"data": {
"jobId": "mdi_1234567890abcdef",
"status": "SUCCEEDED",
"progress": 100,
"currentStage": "completed",
"message": "导入完成",
"compensationStatus": "NOT_REQUIRED",
"updatedAt": "2026-03-12T08:01:30.000Z",
"result": {
"mdfileId": 123,
"resolvedMarkdown": "# Title\n\n",
"html": "<section>...</section>",
"wechatApiHtml": "<section>...</section>",
"imageDirectoryPath": "public/公众号/my-article",
"savedArticle": {
"id": 123,
"mdfileId": 123,
"title": "My Article",
"folder": {
"id": 9,
"name": "公众号",
"fullPath": "公众号"
}
}
}
}
}
{
"code": 200,
"message": "Ok",
"data": {
"jobId": "mdi_1234567890abcdef",
"status": "FAILED_COMPENSATED",
"progress": 100,
"currentStage": "failed",
"message": "导入失败,已回滚上传图片与用户额度",
"compensationStatus": "COMPLETED",
"updatedAt": "2026-03-12T08:02:00.000Z",
"error": {
"message": "Referenced image not found: ./images/cover.png"
}
}
}
SUCCEEDEDFAILED_COMPENSATEDFAILED_PENDING_COMPENSATION and FAILED_COMPENSATION_ERRORresult is returned only when the job succeedserror is returned when the job failsresult.resolvedMarkdown: Markdown after local image paths are replaced with Imgto.link URLsresult.html: Base rendered HTML for preview or debuggingresult.wechatApiHtml: Recommended HTML for submitting to the WeChat Official Account API content fieldresult.mdfileId: The saved Markdown article ID, returned for convenient reuse in the next replace import requestresult.savedArticle: Saved Markdown article record in the editorresult.savedArticle.mdfileId: Stable article identifier to pass back on the next import if you want to replace this article instead of creating a new oneresult.imageDirectoryPath: Final image upload directory pathcurl -X POST "https://api.imgto.link/uploads/md-import" \
-F "archive=@article-package.zip" \
curl -X POST "https://api.imgto.link/api/v1/md/import" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"uploadRelativePath": "inbox/2026/03/12/uuid-article-package.zip",
"archiveFilename": "article-package.zip",
"archiveSize": 345678,
"themeId": "classic",
"directoryPath": "public/articles/demo"
}'
curl -X GET "https://api.imgto.link/api/v1/md/import/jobs/mdi_1234567890abcdef" \
-H "Authorization: Bearer YOUR_API_KEY"
const uploadFormData = new FormData();
uploadFormData.append("archive", zipFile);
const uploadResponse = await fetch("https://api.imgto.link/uploads/md-import", {
method: "POST",
body: uploadFormData
});
const uploadResult = await uploadResponse.json();
const relativePath = uploadResult.data.relativePath;
const createResponse = await fetch("https://api.imgto.link/api/v1/md/import", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
uploadRelativePath: relativePath,
archiveFilename: uploadResult.data.originalFilename,
archiveSize: uploadResult.data.size,
themeId: "classic",
directoryPath: "public/articles/demo"
})
});
const createResult = await createResponse.json();
const jobId = createResult.data.jobId;
let finalResult = null;
for (;;) {
const pollResponse = await fetch("https://api.imgto.link/api/v1/md/import/jobs/" + jobId, {
method: "GET",
headers: {
Authorization: "Bearer YOUR_API_KEY"
}
});
const pollResult = await pollResponse.json();
const job = pollResult.data;
if (job.status === "SUCCEEDED") {
finalResult = job.result;
break;
}
if (job.status === "FAILED_COMPENSATED") {
throw new Error(job.error?.message || "Import failed");
}
await new Promise((resolve) => setTimeout(resolve, 1800));
}
console.log(finalResult.mdfileId);
console.log(finalResult.resolvedMarkdown);
console.log(finalResult.wechatApiHtml);
console.log(finalResult.savedArticle);
Use the result.savedArticle.mdfileId returned by the previous successful import job.
const replaceResponse = await fetch("https://api.imgto.link/api/v1/md/import", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
uploadRelativePath: uploadedZip.data.relativePath,
archiveFilename: uploadedZip.data.originalFilename,
archiveSize: uploadedZip.data.size,
themeId: "classic",
mdfileId: previousResult.savedArticle.mdfileId
})
});
const replaceResult = await replaceResponse.json();
console.log(replaceResult.data.jobId);
mdfileId omitted: create a new import job using the uploaded ZIPmdfileId provided: force this import to replace that exact articlemdfileId from the final successful poll result and keep using it for future updatesUse result.wechatApiHtml from the completed import job for the content field instead of result.html.
const completedImport = await waitForImportJob(jobId);
const wechatApiHtml = completedImport.result.wechatApiHtml;
const draftPayload = {
articles: [
{
title: completedImport.result.savedArticle?.title || "Imported article",
author: "Your Team",
digest: "",
content: wechatApiHtml,
content_source_url: "",
thumb_media_id: "YOUR_WECHAT_THUMB_MEDIA_ID",
need_open_comment: 0,
only_fans_can_comment: 0
}
]
};
const wechatResponse = await fetch(
"https://api.weixin.qq.com/cgi-bin/draft/add?access_token=YOUR_WECHAT_ACCESS_TOKEN",
{
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(draftPayload)
}
);
const wechatResult = await wechatResponse.json();
console.log(wechatResult);
result.wechatApiHtml for WeChat Official Account API publishingresult.html as the content field if you need output aligned with the website's copy/export flowresult.wechatApiHtml should already point to uploaded Imgto.link assetsaccess_token and thumb_media_idwarm): #ea580c, #333china): #7f1d1d, #292524, #f5f5f4cyber): #ec4899, #a855f7, #3b82f6classic): #07c160, #333ink): #3f3f46, #78716ceditorial): #1f2937, #ef4444wenkai): #57534e, #78716cbusiness): #1e3a8a, #1e40afforest): #059669, #ecfdf5azure): #0ea5e9, #e0f2fecoffee): #78350f, #fffbebneon): #d946ef, #06b6d4red): #be123c, #fff1f2silver): #475569, #e2e8f0minimal): #000, #999morandi): #be185d, #fbcfe8sunny): #f97316, #fbbf24mint): #10b981, #d1fae5autumn): #d97706, #fef3c7lavender): #8b5cf6, #ede9fevintage): #7f1d1d, #fecacanotes): #facc15, #fef08agrey): #374151, #f3f4f6entryMarkdown./images/a.png公众号{directoryPath}/{article-slug}If you give this API to an AI coding assistant, tell it:
"Use the async workflow. First upload the ZIP to https://api.imgto.link/uploads/md-import with multipart/form-data and read data.relativePath, data.originalFilename, and data.size. Then call POST https://api.imgto.link/api/v1/md/import with JSON using uploadRelativePath, archiveFilename, and optional themeId, directoryPath, entryMarkdown, saveFolderId, and mdfileId. Authenticate the control-plane API with Authorization: Bearer YOUR_API_KEY. Then poll GET https://api.imgto.link/api/v1/md/import/jobs/{jobId} until status becomes SUCCEEDED or FAILED_COMPENSATED. On success, read result.resolvedMarkdown, result.wechatApiHtml, result.savedArticle, result.mdfileId, and result.imageDirectoryPath. Prefer result.wechatApiHtml when publishing to the WeChat Official Account API content field."