API 文档
集成 RouteMate 配送平台所需的一切内容。
目录
快速开始
RouteMate 集成 API 允许你通过程序导入配送任务、自动优化路线,并从现有系统中查询任务状态。
基础 URL
https://api.routemate.app/v1工作原理
- 创建集成:在 RouteMate Web 应用中进入“集成”,点击“创建集成”。你将获得 client_id 和 client_secret。
- 获取访问令牌:使用凭证换取一个有效期 1 小时的临时 bearer token。
- 导入任务:通过 POST 提交配送停靠点。RouteMate 会对地址进行地理编码、优化路线顺序,并将任务分配给司机。
- 查询状态:你可以随时查看任务进度,确认哪些停靠点已经完成。
要求
- 拥有 Team 或 Enterprise 套餐的 RouteMate 账户
- 已在 RouteMate Web 应用中创建组织
- 已启用并拥有客户端凭证的集成
客户端凭证流程
该 API 使用 OAuth2 客户端凭证。你的 secret 不会被明文保存,我们的服务器仅保存 SHA-256 哈希。
安全模型
- 客户端 secret 会以 SHA-256 哈希形式保存,不会明文存储
- 访问令牌是不透明令牌(不是 JWT),有效期为 1 小时
- 令牌是单次用途并且仅限于你的集成范围
- 所有请求都必须通过 HTTPS 发送
- 每个请求都要携带令牌:Authorization: Bearer <token>
重要: 你的 client_secret 只会在创建集成时显示一次。请安全保存,例如使用环境变量或密钥管理器。如果丢失,必须在 RouteMate 控制台中重新生成。
获取访问令牌
/v1/integration-token请求体
| Field | Type | Required | Description |
|---|---|---|---|
| client_id | string | Yes | 你的集成 client ID(以 rm_ci_ 开头) |
| client_secret | string | Yes | 你的集成 client secret(以 rm_cs_ 开头) |
请求示例
curl -X POST https://api.routemate.app/v1/integration-token \
-H "Content-Type: application/json" \
-d '{
"client_id": "rm_ci_abc123...",
"client_secret": "rm_cs_xyz789..."
}'成功响应 200
{
"access_token": "rm_at_e5988dd1b91a4ff3827c5d2ed416ccbe37ae227a",
"token_type": "Bearer",
"expires_in": 3600
}错误响应
400缺少 client_id 或 client_secret
401凭证无效(secret 错误或 client_id 未知)
403该集成已被禁用
导入任务与停靠点
/v1/integration-import请求头
| Field | Type | Required | Description |
|---|---|---|---|
| Authorization | string | Yes | Bearer <access_token> |
| Content-Type | string | Yes | application/json |
| Idempotency-Key | string | No | 防止重复导入的唯一键(24 小时内有效) |
请求体 — 任务字段
| Field | Type | Required | Description |
|---|---|---|---|
| external_job_id | string | Yes | 你为该任务设置的唯一标识(每个集成内必须唯一) |
| title | string | Yes | 任务标题(例如 Morning Deliveries - Zone A) |
| driver_email | string | Yes | 要分配的司机邮箱。如果司机已有 RouteMate 账户,会在应用中看到路线;否则会创建邀请。 |
| scheduled_date | string | No | 计划日期,ISO 格式(YYYY-MM-DD) |
| timezone | string | No | IANA 时区(例如 Australia/Brisbane 或 America/New_York) |
| metadata | object | No | 附加到任务的自定义键值数据 |
| stops | array | Yes | 停靠点对象数组(见下方停靠点字段) |
请求示例
curl -X POST https://api.routemate.app/v1/integration-import \
-H "Authorization: Bearer rm_at_your_token_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-batch-2026-03-09-001" \
-d '{
"external_job_id": "BATCH-2026-03-09-A",
"title": "Morning Deliveries - Zone A",
"driver_email": "driver@example.com",
"scheduled_date": "2026-03-09",
"timezone": "Australia/Brisbane",
"stops": [
{
"external_stop_id": "ORD-1001",
"address": "1 George St, Brisbane QLD 4000, Australia",
"label": "John Smith",
"notes": "Leave at front door",
"priority": 1,
"parcel_count": 2
},
{
"external_stop_id": "ORD-1002",
"address": "100 Queen St, Brisbane QLD 4000, Australia",
"label": "Jane Doe",
"notes": "Ring doorbell",
"priority": 2
},
{
"external_stop_id": "ORD-1003",
"address": "South Bank Parklands, Brisbane QLD 4101, Australia",
"label": "Bob Wilson",
"priority": 3,
"parcel_count": 1
}
]
}'成功响应 200
{
"job_id": "e7ad097b-bc51-4d01-9b04-0e372d80613a",
"external_job_id": "BATCH-2026-03-09-A",
"route_id": "1c2a8c0b-1b69-4a04-85b1-608b2ebe3878",
"driver_email": "driver@example.com",
"driver_resolved": true,
"driver_user_id": "573b6bee-aa3d-4cb0-af87-620bba0db049",
"stops_imported": 3,
"stops_geocoded": 3,
"stops_geocode_failed": 0,
"optimization": {
"total_distance_km": 12.4,
"total_duration_minutes": 25,
"encoded_polyline": "fvmfDqmfe\\bPtA..."
},
"stops": [
{
"external_stop_id": "ORD-1001",
"address": "1 George St, Brisbane QLD 4000, Australia",
"latitude": -27.4710,
"longitude": 153.0234,
"label": "John Smith",
"notes": "Leave at front door",
"sort_order": 0,
"priority": 1,
"parcel_count": 2,
"status": "pending"
},
{
"external_stop_id": "ORD-1003",
"address": "South Bank Parklands, Brisbane QLD 4101, Australia",
"latitude": -27.4753,
"longitude": 153.0208,
"label": "Bob Wilson",
"notes": null,
"sort_order": 1,
"priority": 3,
"parcel_count": 1,
"status": "pending"
},
{
"external_stop_id": "ORD-1002",
"address": "100 Queen St, Brisbane QLD 4000, Australia",
"latitude": -27.4688,
"longitude": 153.0281,
"label": "Jane Doe",
"notes": "Ring doorbell",
"sort_order": 2,
"priority": 2,
"parcel_count": 1,
"status": "pending"
}
],
"deep_link": "https://app.routemate.app/app/jobs/e7ad097b-...",
"warnings": [
{ "code": "ADDRESS_GEOCODED", "message": "3 stop(s) were geocoded from address text" },
{ "code": "ROUTE_OPTIMIZED", "message": "Route optimized: 12.4 km, 25 min" }
]
}注意: 注意:stops 数组会按照 sort_order 以优化后的配送顺序返回,而不是按你提交的原始顺序。
警告代码
| Field | Type | Required | Description |
|---|---|---|---|
| ROUTE_OPTIMIZED | info | No | 路线已成功优化并返回距离与时长 |
| ADDRESS_GEOCODED | info | No | 一个或多个停靠点已根据地址文本完成地理编码 |
| DRIVER_AUTO_ADDED | info | No | 司机已拥有 RouteMate 账户,并已自动加入你的组织 |
| DRIVER_NOT_FOUND | warning | No | 未找到该邮箱对应的 RouteMate 账户。已创建邀请。 |
| GEOCODE_FAILED | warning | No | 某个停靠点地址无法完成地理编码。请改为提供 latitude/longitude。 |
查询任务状态
/v1/integration-jobs查询参数
| Field | Type | Required | Description |
|---|---|---|---|
| external_job_id | string | No | 你的外部任务 ID(即导入时提供的那个值) |
| job_id | string | No | RouteMate 内部任务 UUID |
必须至少提供 external_job_id 或 job_id 其中一个。
请求示例
curl "https://api.routemate.app/v1/integration-jobs?external_job_id=BATCH-2026-03-09-A" \
-H "Authorization: Bearer rm_at_your_token_here"成功响应 200
{
"job_id": "e7ad097b-bc51-4d01-9b04-0e372d80613a",
"external_job_id": "BATCH-2026-03-09-A",
"title": "Morning Deliveries - Zone A",
"status": "assigned",
"driver_email": "driver@example.com",
"driver_resolved": true,
"driver_user_id": "573b6bee-...",
"route_id": "1c2a8c0b-...",
"scheduled_date": "2026-03-09",
"timezone": "Australia/Brisbane",
"metadata": {},
"stop_count": 3,
"status_counts": {
"pending": 2,
"completed": 1
},
"deep_link": "https://app.routemate.app/app/jobs/e7ad097b-...",
"stops": [
{
"external_stop_id": "ORD-1001",
"address": "1 George St, Brisbane QLD 4000",
"latitude": -27.4710,
"longitude": 153.0234,
"label": "John Smith",
"notes": "Leave at front door",
"status": "completed",
"priority": 1,
"parcel_count": 2
},
...
],
"created_at": "2026-03-09T08:30:00.000Z",
"updated_at": "2026-03-09T10:15:00.000Z"
}任务状态
| Field | Type | Required | Description |
|---|---|---|---|
| pending | status | No | 任务已创建,但司机尚未分配或解析 |
| assigned | status | No | 司机已分配,并可在应用中查看路线 |
| in_progress | status | No | 司机已开始路线 |
| completed | status | No | 所有停靠点都已完成配送 |
停靠点字段
导入请求中每个停靠点可用字段的完整列表。
| Field | Type | Required | Description |
|---|---|---|---|
| external_stop_id | string | Yes | 你为该停靠点设置的唯一标识(在任务内必须唯一) |
| address | string | Yes | 完整街道地址。如果未提供 latitude/longitude,将自动进行地理编码。 |
| latitude | number | No | 十进制度纬度。如果同时提供 longitude,则跳过地理编码。 |
| longitude | number | No | 十进制度经度。如果同时提供 latitude,则跳过地理编码。 |
| label | string | No | 显示标签(例如客户姓名或订单号) |
| notes | string | No | 司机配送说明 |
| service_type | string | No | 服务类型(例如 delivery、pickup 或 service_call) |
| duration_minutes | number | No | 该停靠点的预计服务时长,单位为分钟 |
| time_window_start | string | No | 最早送达时间(ISO 8601 datetime) |
| time_window_end | string | No | 最晚送达时间(ISO 8601 datetime) |
| priority | number | No | 优先级(数值越小优先级越高)。默认值:0 |
| parcel_count | number | No | 该停靠点的包裹数量。默认值:1 |
| metadata | object | No | 附加到该停靠点的自定义键值数据 |
提示: 提示:直接提供 latitude 和 longitude 会比地理编码更快、更可靠。
路线优化
每次导入都会自动优化配送顺序,以减少行驶距离和时间。
优化如何工作
- 所有没有坐标的停靠点都会根据地址文本进行地理编码
- 第一个停靠点被视为起点,最后一个停靠点被视为终点
- 所有中间停靠点都会通过 Google Routes API 优化为最短驾驶路线
- 每个停靠点的 sort_order 字段都会更新为优化后的顺序
- 系统会计算路线折线、总距离和预计时长
响应字段
| Field | Type | Required | Description |
|---|---|---|---|
| optimization.total_distance_km | number | No | 路线总距离,单位公里 |
| optimization.total_duration_minutes | number | No | 预计总驾驶时间,单位分钟 |
| optimization.encoded_polyline | string | No | 用于在地图上绘制路线的 Google Encoded Polyline |
注意: 注意:路线优化至少需要 2 个具有有效坐标的停靠点。如果某些停靠点地理编码失败,系统只会使用成功地理编码的停靠点进行优化。
幂等性
安全重试失败请求而不会创建重复任务。
在导入请求中加入唯一值的 Idempotency-Key 头。如果在 24 小时内发送相同的键,API 会返回第一次成功调用的缓存响应,而不是创建重复任务。
curl -X POST https://api.routemate.app/v1/integration-import \
-H "Authorization: Bearer rm_at_your_token" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: batch-2026-03-09-zone-a" \
-d '{ ... }'
# Safe to retry — same Idempotency-Key returns cached response
curl -X POST https://api.routemate.app/v1/integration-import \
-H "Authorization: Bearer rm_at_your_token" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: batch-2026-03-09-zone-a" \
-d '{ ... }'最佳实践: 在生产环境中始终包含 Idempotency-Key。使用确定性的键,避免网络重试产生重复数据。
错误处理
所有错误都会返回带有 error 字段的 JSON 响应体。
{
"error": "Rate limit exceeded",
"retry_after_seconds": 45
}
// 或者用于验证错误:
{
"error": {
"code": "VALIDATION_ERROR",
"messages": [
"external_job_id is required",
"stops[0].address is required"
]
}
}| 状态 | 含义 | 操作 |
|---|---|---|
| 200 | 成功 | 请求已成功完成 |
| 400 | 错误请求 | 检查错误信息并修正请求体 |
| 401 | 未授权 | 你的令牌无效或已过期。请重新获取。 |
| 403 | 禁止访问 | 你的集成已被禁用。请联系管理员。 |
| 404 | 未找到 | 任务或端点不存在 |
| 405 | 方法不允许 | 请使用正确的 HTTP 方法(POST 或 GET) |
| 429 | 请求过多 | 等待 retry_after_seconds 后再重试 |
| 500 | 服务器错误 | 使用 exponential backoff 后重试。如持续发生请联系支持。 |
速率限制
速率限制按集成在滚动 1 分钟窗口内应用。
| 套餐 | 请求 / 分钟 | 每次导入最大停靠点 |
|---|---|---|
| Team | 60 | 200 |
| Enterprise | Custom | Custom |
发生限流时,API 会返回 HTTP 429,并附带 retry_after_seconds 字段。
完整代码示例
适用于常见语言的复制即用示例。所有示例都展示完整流程:认证、导入和查询。
#!/bin/bash
# RouteMate API Integration Example
API_BASE="https://api.routemate.app/v1"
CLIENT_ID="rm_ci_your_client_id"
CLIENT_SECRET="rm_cs_your_client_secret"
# Step 1: Get access token
TOKEN=$(curl -s -X POST "$API_BASE/integration-token" \
-H "Content-Type: application/json" \
-d "{
\"client_id\": \"$CLIENT_ID\",
\"client_secret\": \"$CLIENT_SECRET\"
}" | jq -r '.access_token')
echo "Access Token: $TOKEN"
# Step 2: Import a job with stops
RESULT=$(curl -s -X POST "$API_BASE/integration-import" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: my-batch-001" \
-d '{
"external_job_id": "BATCH-001",
"title": "Morning Deliveries",
"driver_email": "driver@example.com",
"scheduled_date": "2026-03-10",
"timezone": "Australia/Brisbane",
"stops": [
{
"external_stop_id": "STOP-1",
"address": "1 George St, Brisbane QLD 4000",
"label": "Customer A",
"parcel_count": 2
},
{
"external_stop_id": "STOP-2",
"address": "100 Queen St, Brisbane QLD 4000",
"label": "Customer B",
"notes": "Leave at reception"
}
]
}')
echo "$RESULT" | jq .
# Step 3: Query job status
JOB_ID=$(echo "$RESULT" | jq -r '.job_id')
curl -s "$API_BASE/integration-jobs?job_id=$JOB_ID" \
-H "Authorization: Bearer $TOKEN" | jq .Webhook
当配送完成时获得实时通知。
Webhook 支持即将推出。你将能够注册一个 URL,并接收以下事件的 POST 通知:
- job.completed — 任务中的所有停靠点都已完成配送
- stop.completed — 单个停靠点已完成配送(包含交付证明)
- stop.failed — 一次配送尝试失败
- driver.location — 司机实时 GPS 更新
想提前体验? 联系我们.