Postman 快速调试: 下载 Collection 后导入 Postman,设置 base_url、user_name 和 api_key 变量,即可提交任务并轮询结果。
下载 Postman Collection在请求头中包含您的用户名和 API Key:
如何获取 API Key:使用支持 API 的套餐登录 YazRoute,进入「账户中心」生成。Key 仅显示一次,请妥善保存。
如果您通过 RapidAPI 平台调用接口,认证由平台自动处理:
新求解任务提交限制:按账户套餐区分,限制同一用户每分钟提交的新求解任务总数;结果轮询不计入该限制。系统繁忙时可能返回 429 service_busy;节点数、车辆数、求解时长、月调用额度依套餐不同,详见 套餐页。
通过 YazRoute 直连 API(非 RapidAPI)提交且成功进入队列的请求,会自动写入账户中心的历史规划记录,便于后续查看、下载和复盘。
重点: 你可以自己指定 time_limit_seconds;如果不传,系统会按你当前套餐默认最大求解时间执行。
Webhook 说明: callback_url 为可选参数。提供后,服务器在求解完成时同步发送 HTTP POST 推送(最多阻塞 10 秒),仅尝试一次,不重试。建议你的回调端点在 10 秒内返回 2xx 响应。即使回调超时或失败,求解结果本身不受影响,你仍可通过轮询接口获取结果。注意:回调期间会占用 worker 最多 10 秒,回调端点响应越快越好。
提交接口(POST /api/v1/solve)返回:
查询接口(GET /api/v1/solve/result/{request_id})返回:
轮询时需使用同一账户下任一当前仍有效的 API Key;已删除、已吊销、已禁用或已过期的 Key 无法查询结果。
关于 distances 与 routes:routes 按车辆 id 作为 key(如 "Vehicle 7"),distances 为普通数组;只有实际有路线的车辆会出现在 routes 中。读取 distances[i] 时,请取 routes 按车辆 id 升序后的第 i 个 key 所对应的路线距离,不要默认 distances[i] 一定对应 "Vehicle i"。
说明:任务结果会在有效期(TTL)内保留,便于重复轮询;超过有效期后再次查询会返回 404。
注意:
1. 如果是通过 RapidAPI 调用的用户,认证由 RapidAPI 处理,无需提供 X-User-Name 和 X-Api-Key 请求头。
2. 提交接口是异步的,POST /api/v1/solve 通常只需短超时即可;如需等待最终结果,请对轮询或 webhook 接收链路预留足够时间。
3. 求解时长可配置: 可通过 time_limit_seconds 指定求解时间;若不提供,则默认使用套餐 max_solve_time。
4. 该接口采用异步任务模式:先调用 POST /api/v1/solve 获取 request_id,再轮询 GET /api/v1/solve/result/{request_id} 获取最终结果。
5. 轮询时可通过 result.phase 区分 queued(排队中)与 solving(计算中);当 queued 时可参考 result.queue_depth。
// 接口调用示例(API v1):
// - 先在「账户中心」生成 API Key(仅显示一次)
// - 请求头需携带用户名与 API Key
const userName = 'your_username';
const apiKey = 'your_api_key';
const payload = {
name: 'input_data_sample',
objective: 'min_total_cost',
node_num: 6,
node_positions: [],
vehicle_num: 2,
vehicle_fixed_costs: [100, 120],
vehicle_unit_distance_costs: [1.2, 1.5],
distance_matrix: [
[0, 98, 60, 50, 61, 39],
[94, 0, 67, 60, 36, 91],
[11, 51, 0, 37, 62, 30],
[19, 44, 91, 0, 55, 51],
[27, 69, 75, 41, 0, 36],
[80, 44, 62, 12, 73, 0]
],
start_nodes: [0, 0],
end_nodes: [0, 0],
node_demands: [0, 10, 10, 10, 10, 10],
vehicles_capacity: [100, 100],
node_time_windows: [[0, 500], [0, 500], [0, 500], [0, 500], [0, 500], [0, 500]],
node_service_time: [0, 2, 3, 4, 5, 6],
vehicle_speeds: [30, 30],
max_working_hours: 8,
base_start_time: [9, 0, 0],
// time_limit_seconds 可省略;省略时按当前套餐默认 max_solve_time 执行
time_limit_seconds: 120,
// late_penalty_per_min 可选(元/分钟);>0 时启用软时间窗,允许迟到并计入惩罚成本;省略或 null 时为硬时间窗
// late_penalty_per_min: 10,
// callback_url 可选;提供后服务器求解完成时会同步 POST 一次结果到该地址(最多阻塞 10 秒,不重试)
// callback_url: 'https://your-server.com/webhook/vrp-result'
};
const response = await fetch('https://yazroute.com/api/v1/solve', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-User-Name': userName,
'X-Api-Key': apiKey
},
body: JSON.stringify(payload)
});
// 解析提交响应(异步任务)
const submitData = await response.json();
if (!response.ok || !submitData.success) {
console.error('提交失败:', submitData.error || submitData.detail);
return;
}
const requestId = submitData.request_id;
let finalData = null;
const maxPollMs = 15 * 60 * 1000; // 最多轮询 15 分钟
const pollStart = Date.now();
const backoffMs = [2000, 3000, 5000]; // 推荐轮询退避:2s -> 3s -> 5s
let pollAttempt = 0;
// 轮询最终结果
while (true) {
if (Date.now() - pollStart > maxPollMs) {
console.error('轮询超时,请稍后重试。request_id:', requestId);
break;
}
const pollResp = await fetch(`https://yazroute.com/api/v1/solve/result/${requestId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-User-Name': userName,
'X-Api-Key': apiKey
}
});
const pollData = await pollResp.json();
if (!pollResp.ok) {
console.error('轮询失败:', pollData.error || pollData.detail);
break;
}
if (pollData.result && pollData.result.status === 'processing') {
const phase = pollData.result.phase || 'processing';
if (phase === 'queued') {
console.log('排队中... queue_depth=', pollData.result.queue_depth);
} else if (phase === 'solving') {
console.log('计算中...');
} else {
console.log('处理中... phase=', phase);
}
const waitMs = backoffMs[Math.min(pollAttempt, backoffMs.length - 1)];
pollAttempt += 1;
await new Promise(resolve => setTimeout(resolve, waitMs));
continue;
}
finalData = pollData;
break;
}
if (finalData && finalData.success) {
const result = finalData.result;
console.log('总成本:', result.total_cost);
console.log('求解时间:', result.time, '秒');
console.log('路线数量:', Object.keys(result.routes).length);
console.log('路线详情:', result.routes);
for (const [vehicle, path] of Object.entries(result.routes)) {
console.log(`${vehicle}:`, path);
}
console.log('距离列表:', result.distances);
console.log('载重字典:', result.loads);
console.log('时间窗:', result.time_windows);
} else {
console.error('请求失败:', finalData?.error);
}
// 提交成功响应(POST /api/v1/solve,HTTP 200):
{
"success": true,
"result": {
"status": "accepted",
"phase": "queued",
"message": "Task accepted. Poll /api/v1/solve/result/{request_id} for completion."
},
"error": null,
"request_id": "api_153ca66c55de4162"
}
// 轮询中响应(GET /api/v1/solve/result/{request_id},HTTP 200):
{
"success": true,
"result": {
"status": "processing",
"phase": "queued",
"queue_depth": 3
},
"error": null,
"request_id": "api_153ca66c55de4162"
}
// 轮询成功响应(GET /api/v1/solve/result/{request_id},HTTP 200):
{
"success": true,
"result": {
"success": true,
"error": null,
"total_cost": 273,
"routes": {
"Vehicle 0": [1, 3, 0, 2],
"Vehicle 1": [1, 4, 5, 2]
},
"distances": [139, 134],
"loads": {
"Vehicle 0": [0, 10, 20, 30, 40],
"Vehicle 1": [0, 10, 20, 30, 40]
},
"time_windows": {
"Vehicle 0": [
["09:00:00", "09:02:00"],
["11:02:00", "11:06:00"],
["11:44:00", "11:45:00"],
["13:45:00", "13:48:00"]
],
"Vehicle 1": [
["09:00:00", "09:02:00"],
["10:14:00", "10:19:00"],
["11:31:00", "11:37:00"],
["13:41:00", "13:44:00"]
]
},
"time": 3.04,
"request_id": "api_153ca66c55de4162"
},
"error": null,
"request_id": "api_153ca66c55de4162"
}
API 返回的错误信息均为英文,下方示例为实际返回格式。
// Authentication failed (401) - missing headers:
{
"success": false,
"error": "Missing X-User-Name or X-Api-Key header"
}
// Authentication failed (401) - invalid key:
{
"success": false,
"error": "Invalid username or API Key (or expired/revoked)"
}
// Authentication failed (401) - invalid RapidAPI proxy secret:
{
"success": false,
"error": "Invalid RapidAPI proxy secret"
}
// Exceeds plan limit (400):
{
"success": false,
"error": "Node count (20) exceeds plan limit (15). Please upgrade your plan"
}
// Validation failed (422):
{
"success": false,
"error": "Validation failed",
"detail": [
{
"loc": ["body", "time_limit_seconds"],
"msg": "time_limit_seconds must be a positive integer",
"type": "value_error"
}
]
}
// Validation failed (422) - depot demand must be 0:
{
"success": false,
"error": "Validation failed",
"detail": [
{
"loc": ["body"],
"msg": "Depot/start/end node 1 demand must be 0 (got 10)",
"type": "value_error"
}
]
}
// Forbidden (403) - plan does not support API access:
{
"success": false,
"error": "Your current plan does not support API access. Please upgrade your plan"
}
// Forbidden (403) - polling with a different account (request_id ownership mismatch):
{
"success": false,
"error": "No permission to access this request result"
}
// Too many requests (429) - rate limit:
{
"success": false,
"error": "Too many requests. Please try again later",
"code": "rate_limit_exceeded",
"retry_after_seconds": 60
}
// Too many requests (429) - service busy:
{
"success": false,
"error": "Service is busy. Current queue depth is 3. Please try again later",
"code": "service_busy",
"retry_after_seconds": 10
}
// Too many requests (429) - monthly quota:
{
"success": false,
"error": "Monthly API quota exceeded (500 requests). Please try again next month or upgrade your plan",
"code": "monthly_quota_exceeded"
}
// Solve failed (HTTP 200, success: false):
{
"success": false,
"result": null,
"error": "No feasible solution found. Please review your constraints",
"request_id": "api_153ca66c55de4162"
}
// Result polling failed (404) - request id not found or expired:
{
"success": false,
"error": "Request id not found or expired"
}