简介
OptiRoutes 中的每家公司都有自己的私有文件夹:导入的配送单、已签收的送货单(POD)及其照片和签名、路线导出以及日终报表。文件 API 让您的系统直接读写该文件夹,中间无需 FTP 服务器。
- 地址:
https://srv2.optiroutes.com/api/v1— 仅限 HTTPS。 - 访问:使用公司经理在 OptiRoutes 的 设置 → API 与文件 中创建的 API 密钥。无需联系 OptiRoutes 支持人员。
- 支持系统目前使用的所有文件类型:CSV、JSON、TXT、XLSX/XLS、PDF 和图片。
- 响应 为 JSON,文件下载除外,文件下载直接返回文件本身。
三步开始
- 创建密钥。在 OptiRoutes 中,经理打开 设置 → API 与文件,点击 新建密钥,为其命名(例如“ERP 服务器”),选择权限并复制密钥。密钥只显示一次。
- 检查连接。
curl -H "Authorization: Bearer $OPTIROUTES_KEY" https://srv2.optiroutes.com/api/v1/me - 将今天已签收的 POD 下载为一个 ZIP:
curl -H "Authorization: Bearer $OPTIROUTES_KEY" -o pod.zip "https://srv2.optiroutes.com/api/v1/pod/archive?date=$(date +%F)"
安全 — 请务必阅读
- 像对待密码一样对待密钥。将其保存在服务器上的密钥库或环境变量中。切勿将其放在网页、移动 App、电子邮件、工单或源代码管理中。
- 最小权限。为每个系统分配各自的密钥,并只授予其所需的权限:
pod:read(仅已签收的 POD)、files:read(读取公司的所有文件)、files:write(上传配送单和收件箱文件)。 - 限制地址。如果您的服务器有固定 IP 地址,请将其添加到密钥中(“允许的地址”)。来自其他任何地址的调用都会被拒绝。
- 到期与轮换。密钥可以在若干天后到期。轮换方法:创建新密钥,将系统切换到新密钥,然后吊销旧密钥 — 不会中断服务。
- 立即吊销 可能已泄露的密钥:设置 → API 与文件 → 吊销。密钥会在 30 秒内失效。
- 审计。每次调用都会被记录(时间、地址、文件、响应),并在同一页面中向经理显示。
- OptiRoutes 只保存每个密钥的指纹(SHA-256),从不保存密钥本身。连接仅限 HTTPS(TLS 1.2+)。
- 密钥只能访问其所属公司的文件夹。其他公司的文件和系统的内部文件夹永远无法访问。
身份验证
在每个请求中通过以下任一请求头发送密钥:
Authorization: Bearer opr_2813_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# or
X-API-Key: opr_2813_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx密钥的格式类似 opr_2813_…(公司编号,后接 32 个随机字符)。
公司文件夹
| 文件夹 | 内容 | 写入方 |
|---|---|---|
orders_files/ | OptiRoutes 导入的每日配送单文件:orders_files/YYYY-MM-DD.csv(或 .json / .TXT,按 设置 → 导入 中的设置)。路线导出:orders_files/routes_export_YYYY_MM_DD.csv。 | 您(配送单)· OptiRoutes(导出) |
pod/YYYY/MM/DD/ | 当天已签收的 POD:<order>_sign_….pdf、签名和照片(<order>_….png/jpg)。 | OptiRoutes |
pod/ | 待在司机 App 中签收的原始送货单:pod/<order number>.pdf。 | 您 |
reports/YYYY/MM/ | 日终报表和退货报表。 | OptiRoutes |
podBaseFile/ | POD 空白模板。 | 您 |
inbox/ | 供您移交文件的自由文件夹。 | 您 |
参考
| 调用 | 权限 | 作用 |
|---|---|---|
GET /api/v1/me | 任意 | 检查密钥。返回公司编号、密钥的权限以及您的地址。 |
GET /api/v1/files?folder=<folder> | files:read(pod:read:仅限 pod/) | 列出一级文件夹内容:文件(名称、路径、大小、修改时间)和子文件夹。 |
GET /api/v1/files/download?path=<file> | files:read(pod:read:仅限 pod/) | 下载一个文件。 |
PUT /api/v1/files?path=<file> | files:write | 上传文件(请求正文即文件,或使用带 file 字段的 multipart 表单)。已存在的文件会被替换。最大 50 MB。 |
DELETE /api/v1/files?path=<file> | files:write | 删除您上传的文件(在您有权上传的位置)。 |
GET /api/v1/pod?date=YYYY-MM-DD[&order=<number>] | pod:read | 某一天的 POD 文件,每个文件附带其配送单号和类型:signed_pdf、signature、photo。 |
GET /api/v1/pod/archive?date=YYYY-MM-DD[&kind=signed_pdf] | pod:read | 当天所有 POD 文件打包为一个 ZIP。 |
列表响应示例:
{
"ok": true,
"folder": "pod/2026/10/11/",
"items": [
{ "name": "12345_sign_2026_10_11.pdf", "path": "pod/2026/10/11/12345_sign_2026_10_11.pdf",
"type": "file", "size": 84213, "modified": "2026-10-11T09:14:02.000Z" }
]
}常见任务
上传今天的配送单文件
# curl (Linux / macOS / Windows 10+)
curl -X PUT -H "Authorization: Bearer $OPTIROUTES_KEY" \
--data-binary @orders.csv -H "Content-Type: text/csv" \
"https://srv2.optiroutes.com/api/v1/files?path=orders_files/$(date +%F).csv"
# PowerShell
Invoke-RestMethod -Method Put -InFile .\orders.csv -ContentType 'text/csv' `
-Headers @{ Authorization = "Bearer $env:OPTIROUTES_KEY" } `
-Uri "https://srv2.optiroutes.com/api/v1/files?path=orders_files/$(Get-Date -f yyyy-MM-dd).csv"OptiRoutes 会按现有方式导入该文件(设置 → 导入 中的自动导入,或用户的“导入文件”)。
下载某个配送单已签收的 POD
curl -H "Authorization: Bearer $OPTIROUTES_KEY" "https://srv2.optiroutes.com/api/v1/pod?date=2026-10-11&order=12345"
# then, for each item:
curl -H "Authorization: Bearer $OPTIROUTES_KEY" -OJ "https://srv2.optiroutes.com/api/v1/files/download?path=pod/2026/10/11/12345_sign_2026_10_11.pdf"
下载日终报表
curl -H "Authorization: Bearer $OPTIROUTES_KEY" "https://srv2.optiroutes.com/api/v1/files?folder=reports/2026/10/"
curl -H "Authorization: Bearer $OPTIROUTES_KEY" -OJ "https://srv2.optiroutes.com/api/v1/files/download?path=reports/2026/10/report_2026_10_11.csv"
Python
import os, datetime, requests
BASE = "https://srv2.optiroutes.com/api/v1"
H = {"Authorization": f"Bearer {os.environ['OPTIROUTES_KEY']}"}
# upload today's orders
day = datetime.date.today().isoformat()
with open("orders.csv", "rb") as f:
r = requests.put(f"{BASE}/files", params={"path": f"orders_files/{day}.csv"},
data=f, headers={**H, "Content-Type": "text/csv"}, timeout=60)
r.raise_for_status()
# download every signed POD of the day
pods = requests.get(f"{BASE}/pod", params={"date": day}, headers=H, timeout=60).json()["items"]
for p in pods:
if p["kind"] == "signed_pdf":
data = requests.get(f"{BASE}/files/download", params={"path": p["path"]}, headers=H, timeout=60)
open(p["name"], "wb").write(data.content)
C# (.NET)
using var http = new HttpClient { BaseAddress = new Uri("https://srv2.optiroutes.com/api/v1/") };
http.DefaultRequestHeaders.Authorization =
new("Bearer", Environment.GetEnvironmentVariable("OPTIROUTES_KEY"));
// upload today's orders
var day = DateTime.Today.ToString("yyyy-MM-dd");
using var content = new ByteArrayContent(File.ReadAllBytes("orders.csv"));
content.Headers.ContentType = new("text/csv");
(await http.PutAsync($"files?path=orders_files/{day}.csv", content)).EnsureSuccessStatusCode();
// the day's PODs as one ZIP
var zip = await http.GetByteArrayAsync($"pod/archive?date={day}");
File.WriteAllBytes($"pod-{day}.zip", zip);
Node.js
const BASE = 'https://srv2.optiroutes.com/api/v1';
const H = { Authorization: `Bearer ${process.env.OPTIROUTES_KEY}` };
const day = new Date().toISOString().slice(0, 10);
// list and download the day's signed PODs (Node 18+)
const { items } = await (await fetch(`${BASE}/pod?date=${day}`, { headers: H })).json();
for (const p of items.filter((i) => i.kind === 'signed_pdf')) {
const res = await fetch(`${BASE}/files/download?path=${encodeURIComponent(p.path)}`, { headers: H });
await require('fs/promises').writeFile(p.name, Buffer.from(await res.arrayBuffer()));
}像 FTP 一样工作 — 文件夹同步脚本
以前使用 FTP 的团队可以让自己服务器上的某个文件夹与公司文件夹保持同步:一个计划任务下载新文件(例如 POD),并上传您放入本地文件夹的文件。下面的 PowerShell 脚本可同时完成这两项;请通过 Windows 任务计划程序每隔几分钟运行一次(在 Linux 上,请将 curl 命令与 cron 配合使用)。
# optiroutes-sync.ps1 — download new PODs, upload what is in .\outbox (run every 5 minutes)
$Base = 'https://srv2.optiroutes.com/api/v1'
$H = @{ Authorization = "Bearer $env:OPTIROUTES_KEY" }
$Local = 'C:\OptiRoutes'
New-Item -ItemType Directory -Force "$Local\pod", "$Local\outbox", "$Local\sent" | Out-Null
# 1. today's and yesterday's PODs -> C:\OptiRoutes\pod\YYYY-MM-DD\
foreach ($d in (Get-Date), (Get-Date).AddDays(-1)) {
$day = $d.ToString('yyyy-MM-dd'); $dir = "$Local\pod\$day"
New-Item -ItemType Directory -Force $dir | Out-Null
$list = Invoke-RestMethod -Headers $H -Uri "$Base/pod?date=$day"
foreach ($f in $list.items) {
$dest = Join-Path $dir $f.name
if (-not (Test-Path $dest)) {
Invoke-WebRequest -Headers $H -OutFile $dest -Uri ("$Base/files/download?path=" + [uri]::EscapeDataString($f.path))
}
}
}
# 2. every file in C:\OptiRoutes\outbox -> orders_files/, then moved to C:\OptiRoutes\sent
Get-ChildItem "$Local\outbox" -File | ForEach-Object {
Invoke-RestMethod -Method Put -Headers $H -InFile $_.FullName -ContentType 'application/octet-stream' `
-Uri ("$Base/files?path=" + [uri]::EscapeDataString("orders_files/" + $_.Name)) | Out-Null
Move-Item $_.FullName "$Local\sent\" -Force
}将公司从 FTP 迁移到 API
经理在 设置 → API 与文件 → 文件传输方式:API 中切换。从那一刻起,不会再向公司的 FTP 发送任何内容,所有文件都改为存放在公司文件夹中:
| 使用 FTP | 使用 API |
|---|---|
| 您将配送单文件放到 FTP 上 | PUT /api/v1/files?path=orders_files/YYYY-MM-DD.csv |
已签收的 POD 推送到您 FTP 上的 /POD/ | GET /api/v1/pod?date=… / /api/v1/pod/archive?date=… |
路线导出推送到 /orders/ | orders_files/routes_export_YYYY_MM_DD.csv |
报表推送到 /orders/YYYY/MM/ | reports/YYYY/MM/ |
新公司从一开始就使用 API。切换回 FTP 使用同一个开关。
使用旧 OptiRoutes 服务器的公司
仍在使用旧 OptiRoutes 服务器(WEB)的公司可以通过 API 获取其已签收的 POD:创建一个具有 pod:read 权限的密钥,并使用 /api/v1/pod、/api/v1/pod/archive 和 /api/v1/files/download?path=pod/…。其他文件仍按目前的方式传输,直到公司迁移到新服务器。
错误
出错时的响应为 {"ok": false, "error": "<code>", "message": "<explanation>"}。
| HTTP | error | 处理方法 |
|---|---|---|
| 401 | missing_key / invalid_key | 发送密钥;检查密钥是否已被吊销或已过期。 |
| 403 | scope_missing | 密钥缺少该权限 — 请创建具有该权限的密钥。 |
| 403 | ip_not_allowed | 从允许的地址调用,或更新密钥的地址。 |
| 403 | folder_read_only | 只能上传到 orders_files/、inbox/、podBaseFile/ 或 pod/<file>.pdf。 |
| 400 | invalid_path / invalid_date | 路径为相对路径(orders_files/a.csv),日期格式为 YYYY-MM-DD。 |
| 404 | not_found / no_pod_files | 没有该文件 / 当天没有 POD。 |
| 413 | file_too_large | 每个文件最大 50 MB。 |
| 429 | rate_limited | 请等待一分钟后重试。 |
| 502 / 503 | storage_unavailable / files_api_unavailable | 暂时性问题 — 请一分钟后重试。 |
限制
- 每个密钥每分钟 300 个请求。
- 每个文件 50 MB。
- 每家公司 20 个有效密钥。
- 一次文件夹列表最多返回 5,000 个条目;如需更多,请列出子文件夹(例如某一天的 POD)。
帮助
公司经理可以在 设置 → API 与文件 中查看每个密钥、其最后使用时间以及最近的调用。如有其他问题,请联系 OptiRoutes 支持人员,并提供公司编号和调用时间 — 切勿发送密钥本身。