Wazo REST API 使用详解

Wazo Platform v26.10 REST API 全解——confd/auth/webhookd/sysconfd 四大服务、User+Line+Extension 绑定实战、Webhook 事件推送、WebSocket 实时事件、ACL 权限模型与 SDK

WazoWazoPBXSIP 协议VoIP 语音Asterisk PBX统一通信2026/10/27

Wazo REST API 使用详解

目标:完整梳理 Wazo Platform v26.10 的 REST API 体系——认证流程、四大服务 API 矩阵(confd/auth/webhookd/sysconfd)、配置 CRUD 实战示例(User + Line + Extension 绑定完整链路)、事件推送、错误码约定与 ACL 权限模型。所有命令都是真实可执行的 curl 调用,响应 JSON 为结构示例(生产数据会不同)。

一、环境信息

  • Wazo Platform 版本:26.10(2026-10-12 发布)
  • API 版本:confd 1.1、auth 0.1、webhookd 1.0、sysconfd 1.0
  • 基础 URL:https://<你的 Wazo IP 或域名>/api(通过 Nginx 统一入口)
  • 官方 OpenAPI 控制台:https://wazo-platform.org/documentation (填入你的 Wazo IP 即可在线调用)
  • 本文查询日期:2026-10-27

二、API 总览

2.1 四大 API 服务

Wazo 的 REST API 由四个微服务分别提供,每个服务有独立的端口和 URL 前缀,对外统一经 Nginx 反代到 :443/api/<服务>/ 路径:

服务Nginx 前缀直接端口职责
wazo-confd/api/confd/1.1/127.0.0.1:9486PBX 配置 CRUD——用户、分机、中继、IVR、队列、语音信箱、会议
wazo-auth/api/auth/0.1/127.0.0.1:9497认证鉴权——用户登录、token 生成、ACL 策略、OAuth2
wazo-webhookd/api/webhookd/1.0/127.0.0.1:9800Webhook 管理——事件到 HTTP endpoint 的推送规则
wazo-sysconfd/api/sysconfd/1.0/127.0.0.1:8668系统管理——网络接口、resolv.conf 等服务器侧配置

2.2 confd API 资源矩阵(最核心、最常用)

wazo-confd 是 Wazo 的配置中枢,覆盖 50+ 资源端点:

资源方法说明
/usersGET/POST用户(SIP account 上层抽象)
/users/{uuid}GET/PUT/DELETE单个用户
/linesGET/POST物理分机(PJSIP/SCCP 注册端点)
/extensionsGET/POST逻辑分机(短号,如 1001)
/pjsipGET/POSTPJSIP trunk / endpoint
/incallsGET/POST入呼规则(按时间/来向匹配)
/outcallsGET/POST出呼规则(选择中继组、前缀剥离)
/trunksGET/POSTSIP trunk(运营商对接)
/queuesGET/POST呼叫队列(ACD)
/groupsGET/POST静态组(同时振铃)
/voicemailsGET/POST语音信箱
/meetingsGET/POST会议(MeetMe/BConfBridge)
/ivrGET/POST自动语音应答
/funckeysGET/POST功能键配置
/contact_directoriesGET/POST通讯录
/agentsGET/POST坐席(Agent)
/agent-skillGET/POST坐席技能(Skills-based Queue)
/infosGET系统版本与 UUID(不需要认证但返回有限)
/cdrGET通话详细记录(只读查询)

2.3 通用 URL 参数

confd 支持统一的查询过滤参数:

GET /1.1/<resource>?limit=X&offset=Y&order=col&direction=asc|desc&search=keyword
参数说明
limit返回条数上限
offset跳过前 N 条
order按某列排序
directionasc 或 desc
search关键字模糊搜索

三、认证与首次调用

3.1 认证流程三步曲

[你的应用] → POST /api/auth/0.1/token(带用户密码) → 拿到 token
[你的应用] → 每个请求 Header 带 X-Auth-Token: <token>
[Wazo] → 校验 token + ACL → 返回数据

注意:所有 REST API 都是 HTTPS,Wazo 用自签证书,curl 需加 -k 跳过验证。

3.2 获取 token

方式一:直接 curl(推荐,无需在服务器上装 wazo-auth-cli):

# 把 wazo.example.com 换成你的 Wazo 地址
# rest-api-user / q1w2e3r4 是安装向导里设置的 API 用户
curl -sk -X POST \
  -u rest-api-user:q1w2e3r4 \
  -H 'Content-Type: application/json' \
  -d '{"expiration": 3600}' \
  https://wazo.example.com/api/auth/0.1/token | python3 -m json.tool

# 典型响应:
# {
#     "data": {
#         "expires_at": "2026-10-27T23:50:15+08:00",
#         "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NjE2MzIwMTV9.xxxxxxxxxxxxxxxxxxxxxx"
#     },
#     "application": {
#         "name": "rest-api-user",
#         "uuid": "b3e8f291-485a-4f0b-bc1d-7e9a2f3c4b5e"
#     }
# }

方式二:服务器上用 wazo-auth-cli:

wazo-auth-cli token create \
  --auth-user rest-api-user \
  --auth-password q1w2e3r4 2>/dev/null

# 输出同上,直接 JSON

3.3 验证 token 并获取系统信息

export TOKEN="从上面复制的 token 值"

# 获取 Wazo 版本
curl -sk -X GET \
  -H "X-Auth-Token: ${TOKEN}" \
  https://wazo.example.com/api/confd/1.1/infos | python3 -m json.tool

# 响应:
# {
#     "wazo_version": "26.10",
#     "version": "26.10",
#     "uuid": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
#     "stat_socket_path": "/var/run/wazo-asterisk/ami/wazo"
# }

3.4 ACL 权限模型

💡 技术拓展:Wazo 的 ACL(Access Control List)和常见 RBAC(Role-Based Access Control)是两套不同的设计——

模型代表权限表达适合场景
RBACKubernetes / 大多数 SaaSRole 绑定一组 Permission角色清晰的场景(admin/operator/user)
Wazo ACLWazo Platform"confd.users.create"、"auth.#"、"websocket" 这种点分路径 + # 通配微服务细粒度权限,每个服务自己暴露 ACL 路径

Wazo ACL 示例:

  • "auth.#" → 拥有所有 auth 端点权限
  • "confd.users.read" → 只读 confd 的 users 资源
  • "websocket" → 允许建立 WebSocket 实时事件连接
  • "cdr.#" → 允许查询 CDR(通话记录)

创建一个"只能读 confd 和查 CDR"的受限 API 用户:

# 1. 创建 ACL 策略(Policy)
curl -sk -X POST \
  -H "X-Auth-Token: ${TOKEN}" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "readonly-ops",
    "acl": [
      "confd.users.read",
      "confd.lines.read",
      "confd.extensions.read",
      "confd.trunks.read",
      "confd.queues.read",
      "cdr.#"
    ]
  }' \
  https://wazo.example.com/api/auth/0.1/policies | python3 -m json.tool
# → 返回 policy uuid

# 2. 创建 API 用户并绑定 Policy
curl -sk -X POST \
  -H "X-Auth-Token: ${TOKEN}" \
  -H 'Content-Type: application/json' \
  -d '{
    "username": "readonly",
    "password": "q1w2e3r4",
    "purpose": "external_api",
    "enabled": true
  }' \
  https://wazo.example.com/api/auth/0.1/users

# 3. 把 Policy 绑定到用户
curl -sk -X PUT \
  -H "X-Auth-Token: ${TOKEN}" \
  "https://wazo.example.com/api/auth/0.1/users/<user_uuid>/policies/<policy_uuid>"

四、配置 CRUD 实战

4.1 核心概念:User ↔ Line ↔ Extension 三角绑定

这是理解 Wazo 配置的最关键概念——三者是分离的,需要分别创建再绑定:

User(抽象人 / 账号)
   ↓ 绑定到
Line(物理 SIP 注册端点)
   ↓ 绑定到
Extension(逻辑短号,如 1001)

4.2 完整链路:创建一个可用 SIP 分机

Step 1:创建 User

curl -sk -X POST \
  -H "X-Auth-Token: ${TOKEN}" \
  -H 'Content-Type: application/json' \
  -d '{
    "firstname": "张三",
    "lastname": "技术部",
    "username": "zhangsan",
    "password": "q1w2e3r4",
    "mobile_phone_number": "13800138000",
    "email": "zhangsan@example.com"
  }' \
  https://wazo.example.com/api/confd/1.1/users | python3 -m json.tool

# 响应:
# {
#     "id": "7d4b4b2c-2a11-45c5-8b1a-9f8c6a4b3d2e",   ← 记下这个 user uuid
#     "firstname": "张三",
#     "lastname": "技术部",
#     ...
# }

Step 2:创建 Extension(逻辑分机号)

curl -sk -X POST \
  -H "X-Auth-Token: ${TOKEN}" \
  -H 'Content-Type: application/json' \
  -d '{
    "exten": "1001",
    "context": "default",
    "type": "user"
  }' \
  https://wazo.example.com/api/confd/1.1/extensions | python3 -m json.tool

# 响应(节选):
# {
#     "id": "4a8e3b1c-...",      ← extension uuid
#     "exten": "1001",
#     ...
# }

Step 3:创建 Line(PJSIP SIP 账号)

curl -sk -X POST \
  -H "X-Auth-Token: ${TOKEN}" \
  -H 'Content-Type: application/json' \
  -d '{
    "protocol": "pjsip",
    "name": "张三-1001",
    "config": {
      "username": "zhangsan-1001",
      "secret": "q1w2e3r4",
      "context": "default",
      "transport": "udp",
      "codec_prefs": ["ulaw", "alaw", "opus"],
      "nat": {"force_rport": true, "rewrite_contact": true}
    }
  }' \
  https://wazo.example.com/api/confd/1.1/lines | python3 -m json.tool

# 响应(节选):
# {
#     "id": "c3b9e2f1-...",       ← line uuid
#     "protocol": "pjsip",
#     ...
# }

Step 4:把 Extension 绑定到 Line

# 先记下 extension uuid 和 line uuid
EXTENSION_UUID="从上一步复制"
LINE_UUID="从上一步复制"

curl -sk -X PUT \
  -H "X-Auth-Token: ${TOKEN}" \
  "https://wazo.example.com/api/confd/1.1/lines/${LINE_UUID}/extension/${EXTENSION_UUID}"

# 返回 HTTP 204 No Content,没 body 是正常的

Step 5:把 Line 绑定到 User

USER_UUID="从 Step 1 复制"
LINE_UUID="从 Step 3 复制"

curl -sk -X PUT \
  -H "X-Auth-Token: ${TOKEN}" \
  "https://wazo.example.com/api/confd/1.1/users/${USER_UUID}/lines/${LINE_UUID}"

# HTTP 204

Step 6:验证绑定结果

# 列出用户及其所有绑定
curl -sk -H "X-Auth-Token: ${TOKEN}" \
  "https://wazo.example.com/api/confd/1.1/users/${USER_UUID}" | python3 -m json.tool

# 响应:
# {
#     "id": "7d4b4b2c-...",
#     "firstname": "张三",
#     "lines": ["c3b9e2f1-..."],      ← 已绑定
#     "extensions": ["4a8e3b1c-..."],  ← 已绑定
#     ...
# }

到这一步,话机配置 SIP 账号 zhangsan-1001 / q1w2e3r4 就能注册到 Wazo 了。注意绑定后 Asterisk 配置自动 reload,不需要手动重启。

4.3 创建一个入呼规则(Incall)

入呼规则(Incall)决定"某个 DID 号码呼进来后怎么路由":

curl -sk -X POST \
  -H "X-Auth-Token: ${TOKEN}" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "销售热线",
    "extensions": [
        {"exten": "5551234", "context": "default"}
    ],
    "destination": {
        "type": "queue",
        "value": "queue-uuid-xxxxx"
    },
    "caller_id_mode": "default",
    "enabled": true
  }' \
  https://wazo.example.com/api/confd/1.1/incalls | python3 -m json.tool

4.4 创建一个 SIP Trunk(出呼用)

curl -sk -X POST \
  -H "X-Auth-Token: ${TOKEN}" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "运营商A",
    "context": "default",
    "protocol": "pjsip",
    "config": {
        "sip_version": "RFC3261",
        "auth": {
            "username": "trunk-user",
            "password": "trunk-password"
        },
        "register": {
            "sip_server": "sip.carrier-a.com",
            "transport": "tcp"
        },
        "endpoint": {
            "outbound_auth": {
                "username": "trunk-user",
                "password": "trunk-password"
            },
            "aor": {
                "contact": "sip:trunk-user@sip.carrier-a.com"
            },
            "auth": {
                "username": "trunk-user",
                "password": "trunk-password"
            }
        }
    }
  }' \
  https://wazo.example.com/api/confd/1.1/trunks | python3 -m json.tool

4.5 查询 CDR(通话记录)

# 查最近 10 条通话
curl -sk -H "X-Auth-Token: ${TOKEN}" \
  "https://wazo.example.com/api/confd/1.1/cdr?limit=10&direction=asc" | python3 -m json.tool

# 响应:
# {
#     "total": 1024,
#     "items": [
#         {
#             "id": "1",
#             "date": "2026-10-27T14:20:10",
#             "duration": 45,
#             "type": "internal",
#             "source_name": "张三",
#             "source_exten": "1001",
#             "destination_exten": "1002",
#             "destination_name": "李四",
#             "answer": "2026-10-27T14:20:12",
#             "end": "2026-10-27T14:20:55",
#             "recordings": ["2026/10/27/1/call-recording.wav"]
#         },
#         ...
#     ]
# }

五、Webhookd:事件推送

5.1 简介

wazo-webhookd 把 PBX 事件(来电振铃、接通、挂机、录音完成等)推送到你指定的 HTTP endpoint。适合开发 CRM 弹屏、监控告警等集成。

5.2 注册一个 Webhook

curl -sk -X POST \
  -H "X-Auth-Token: ${TOKEN}" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "CRM 来电弹屏",
    "url": "https://crm.example.com/webhooks/wazo",
    "events": [
        "call_created",
        "call_answered",
        "call_ended",
        "voicemail_received"
    ],
    "method": "POST",
    "body": "form-data",
    "verify_certificate": true,
    "timeout": 10
  }' \
  https://wazo.example.com/api/webhookd/1.0/subscriptions | python3 -m json.tool

5.3 支持的事件类型

事件说明
call_created来电振铃时(刚进入拨号计划)
call_answered通话接通
call_ended通话结束(包含挂机原因)
call_hangup任意一端挂机
voicemail_received新语音信箱留言
meeting_started / meeting_ended会议开始 / 结束
agent_status坐席状态变更(Ready/Busy/DND)
recording_started / recording_ended录音开始 / 结束
user_created / user_deleted用户变更

5.4 推送 Payload 示例(call_ended)

{
  "event_name": "call_ended",
  "data": {
    "call_id": "SIP/trunk-inbound-00000042",
    "source_number": "5551234",
    "source_name": "外部来电",
    "destination_number": "5556789",
    "destination_name": "销售热线",
    "answer_time": "2026-10-27T14:20:12Z",
    "end_time": "2026-10-27T14:20:55Z",
    "hangup_cause": "NORMAL_CLEARING",
    "duration_seconds": 43
  },
  "timestamp": "2026-10-27T14:20:55Z"
}

六、WebSocket 实时事件

6.1 建立连接

WebSocket 端点:wss://<Wazo>/ws/?token=<你的 auth token>

# Python 示例
import asyncio, websockets, json

TOKEN = "从 auth 拿到的 token"
URI = f"wss://wazo.example.com/ws/?token={TOKEN}"

async def listen():
    async with websockets.connect(URI, ssl=False) as ws:
        while True:
            msg = await ws.recv()
            data = json.loads(msg)
            print(f"[{data['wazo_tenant_uuid']}] {data['name']}: {json.dumps(data['data'])}")

asyncio.run(listen())

6.2 事件输出示例

[tenant-uuid-xxx] CallCreated: {"call_id":"SIP/2001-00000012","source":"5551234","destination":"2001"}
[tenant-uuid-xxx] CallAnswered: {"call_id":"SIP/2001-00000012","answered_by":"sip:2001@10.0.0.50"}
[tenant-uuid-xxx] CallEnded:   {"call_id":"SIP/2001-00000012","end_time":"2026-10-27T14:30:00Z","duration":120}
[tenant-uuid-xxx] UserStatusUpdate: {"user_uuid":"user-xxx","status":"busy"}

七、REST API 错误码与响应约定

7.1 HTTP 状态码

码含义常见场景
200成功GET 查询 / PUT 修改
201创建成功POST 创建(响应体含新资源)
204删除或无响应PUT/PATCH 成功、DELETE 成功
400请求参数错误body JSON 格式错、必填字段缺失
401未认证token 缺失、过期
403禁止ACL 没有对应权限
404资源不存在uuid 拼错 / 资源已被删除
412前置条件失败User + Line 绑定前 User 必须存在
500服务器内部错误查 journalctl -u wazo-confd 日志

7.2 错误响应格式

confd 返回数组形式(哪怕只有一个错误):

# 示例:创建用户时漏填 必填字段
curl -sk -X POST \
  -H "X-Auth-Token: ${TOKEN}" \
  -H 'Content-Type: application/json' \
  -d '{"firstname":"测试"}' \
  https://wazo.example.com/api/confd/1.1/users | python3 -m json.tool

# 响应:
# [
#     "Error(s) while validating data",
#     "lastname: Missing data for required field",
#     "username: Missing data for required field"
# ]

八、分页 / 过滤 / 排序实战

# 分页:第 3 页,每页 50 条
curl -sk -H "X-Auth-Token: ${TOKEN}" \
  "https://wazo.example.com/api/confd/1.1/users?limit=50&offset=100" | python3 -m json.tool
# 响应:
# {
#     "total": 237,          ← 总条数
#     "items": [ ... 50 条 ... ]
# }

# 搜索:按分机号或用户名模糊匹配
curl -sk -H "X-Auth-Token: ${TOKEN}" \
  "https://wazo.example.com/api/confd/1.1/users?search=zhangsan&limit=10"

# 排序:按创建时间倒序
curl -sk -H "X-Auth-Token: ${TOKEN}" \
  "https://wazo.example.com/api/confd/1.1/users?order=created_at&direction=desc&limit=10"

九、常见问题(FAQ)

Q1: curl 报错 "SSL certificate problem: self signed certificate"?

加 -k 跳过验证即可:

curl -sk ... https://wazo.example.com/api/confd/1.1/infos

生产环境建议配 CA 证书或 Let's Encrypt,然后用 --cacert 指定 CA。

Q2: token 过期了怎么办?

Wazo token 默认有效期 3600 秒(1 小时)。过期后所有请求返回 401。两种应对:

  1. Web 应用:用 WebSocket 监听 token 过期事件(会触发 4003 close frame),自动重新获取
  2. 服务端脚本:捕获 401 后重新 POST /auth/0.1/token 获取,重试原请求

Q3: 创建 PJSIP Trunk 后注册不上运营商?

排查步骤:

# 1. 先看 wazo-confd 里 trunk 是否创建成功
curl -sk -H "X-Auth-Token: ${TOKEN}" \
  "https://wazo.example.com/api/confd/1.1/trunks?search=运营商A"

# 2. 看 Asterisk PJSIP 注册状态
asterisk -rx "pjsip show registrations"
# 应该看到 "Registered";如果是 "Rejected" 或 没记录 → 继续

# 3. 看 Asterisk 日志
tail -50 /var/log/asterisk/full
# 搜 "registration" / "401" / "403" 关键字

# 4. 确认运营商要求的注册方式(IP auth vs 用户名密码)

Q4: confd API 调用返回 403 "forbidden"?

你的 API 用户缺少对应的 ACL。需要:

# 用 root token 给用户加策略
curl -sk -X PUT \
  -H "X-Auth-Token: <root_token>" \
  "https://wazo.example.com/api/auth/0.1/users/<user_uuid>/policies/<policy_uuid>"

常用 ACL 速查:

ACL允许的操作
confd.#所有 confd 端点
confd.users.create创建用户
confd.users.read只读用户
auth.#所有 auth 端点
websocketWebSocket 实时事件
cdr.#查询 CDR
webhookd.#管理 Webhook

Q5: 有没有 Python SDK 可用?

有——wazo-sdk:

pip install wazo-sdk

基本用法:

from wazo_auth_client import Client as AuthClient
from wazo_confd_client import Client as ConfdClient

# 认证
auth = AuthClient(host="wazo.example.com", verify_certificate=False)
token = auth.token.new(username="rest-api-user", password="q1w2e3r4", expiration=3600)["token"]

# 使用 confd
confd = ConfdClient(host="wazo.example.com", token=token, verify_certificate=False)
users = confd.users.list()
for u in users["items"]:
    print(u["firstname"], u["lastname"], u["username"])

十、参考链接

链接说明
https://wazo-platform.org/documentationWazo 官方 OpenAPI 控制台(填入 IP 后在线调用)
https://wazo-platform.org/uc-doc/api_sdk/rest_api/REST API 文档总入口
https://wazo-platform.org/uc-doc/api_sdk/rest_api/conventions/REST API 约定(状态码、参数格式)
https://wazo-platform.org/uc-doc/api_sdk/rest_api/quickstart/API 快速入门
https://wazo-platform.org/uc-doc/api_sdk/rest_api/examplesREST API 实战示例(含 curl / Python)
https://wazo-platform.org/documentation/console/configurationconfd 在线 Swagger 控制台
https://wazo-platform.org/uc-doc/contributors/network各服务端口与网络要求
https://www.quzuo.net/document/6ijNclQUrvYh本平台 Wazo Debian 12 安装指南
https://www.quzuo.net/document/wKBUGZqNuuED本平台 Wazo 配置参数详解