@qoniai/qoni 0.9.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +203 -0
- package/README.md +548 -76
- package/README.zh-CN.md +443 -53
- package/dist/index.cjs +15082 -699
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25826 -243
- package/dist/index.d.ts +25826 -243
- package/dist/index.js +15077 -698
- package/dist/index.js.map +1 -1
- package/docs/authing-sdk-LICENSE.txt +21 -0
- package/docs/delivery-examples/README.md +44 -0
- package/docs/delivery-examples/README.zh-CN.md +44 -0
- package/docs/delivery-examples/agents.ts +26 -0
- package/docs/delivery-examples/failure-handling.ts +21 -0
- package/docs/delivery-examples/hosted-login.ts +40 -0
- package/docs/delivery-examples/interactions.ts +30 -0
- package/docs/delivery-examples/local-consumer.mjs +159 -0
- package/docs/delivery-examples/m2-r2/README.md +20 -0
- package/docs/delivery-examples/m2-r2/README.zh-CN.md +20 -0
- package/docs/delivery-examples/m2-r2/local-consumer.mjs +53 -0
- package/docs/delivery-examples/m2-r2/memory-outcome.ts +22 -0
- package/docs/delivery-examples/m2-r2/package.json +1 -0
- package/docs/delivery-examples/m2-r2/tsconfig.json +1 -0
- package/docs/delivery-examples/package.json +5 -0
- package/docs/delivery-examples/profile-memory.ts +30 -0
- package/docs/delivery-examples/tsconfig.json +4 -0
- package/docs/genauth-communication.md +1410 -0
- package/docs/genauth-management-api.md +597 -0
- package/docs/genauth-management.md +285 -0
- package/docs/ordinary-task-profile.md +18 -0
- package/docs/quickstart-v5-contract.md +39 -0
- package/package.json +17 -7
- package/skills/qoni-sdk/SKILL.md +177 -7
|
@@ -0,0 +1,1410 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Agent Mail 与 Agent Phone SDK
|
|
3
|
+
description: 使用 Qoni Node.js SDK 管理 Agent 邮箱、号码、通信任务和供应商配置。
|
|
4
|
+
status: draft
|
|
5
|
+
sdkCandidate: contracts/genauth-communication.json
|
|
6
|
+
lastReviewed: 2026-10-12
|
|
7
|
+
pageClass: qoni-sdk-communication
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 初始化
|
|
11
|
+
|
|
12
|
+
管理接口使用 Qoni 访问密钥;邮箱和短信业务接口还需配置同一用户池的 GenAuth 访问密钥。
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { Qoni } from '@qoniai/qoni'
|
|
16
|
+
|
|
17
|
+
const qoni = new Qoni({
|
|
18
|
+
accessKey: process.env.QONI_ACCESS_KEY!,
|
|
19
|
+
secretKey: process.env.QONI_SECRET_KEY!,
|
|
20
|
+
genauthCommunicationCredentials: {
|
|
21
|
+
accessKeyId: process.env.GENAUTH_ACCESS_KEY_ID!,
|
|
22
|
+
accessKeySecret: process.env.GENAUTH_ACCESS_KEY_SECRET!,
|
|
23
|
+
userPoolId: process.env.GENAUTH_USER_POOL_ID!,
|
|
24
|
+
},
|
|
25
|
+
})
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
| 入口 / 选项 | 说明 |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| `agentMail.*`、`agentPhone.*` | 邮箱、短信、号码及验证码操作 |
|
|
31
|
+
| `agentMail.admin.*`、`agentPhone.admin.*` | 供应商、权限及通信资源管理 |
|
|
32
|
+
| `genauthCommunicationCredentials` | 原生 `{ accessKeyId, accessKeySecret, userPoolId }`,或标准 `{ accessToken, userPoolId }` |
|
|
33
|
+
| `genauthHost` | 可选。私有部署地址;默认通过 Qoni 运行时发现 |
|
|
34
|
+
| `timeoutMs` | 单次 HTTP 请求超时,默认 `30000` 毫秒 |
|
|
35
|
+
| 第二参数 `{ signal }` | 取消当前请求;等待方法同时取消睡眠 |
|
|
36
|
+
|
|
37
|
+
单次调用可通过 `accessToken` / `userPoolId` 指定业务凭据,通过 `adminToken` / `userPoolId` 指定管理凭据。也可以绑定凭据后复用客户端:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
const mail = qoni.genauth.agentMail.withCredentials({
|
|
41
|
+
accessKeyId: process.env.GENAUTH_ACCESS_KEY_ID!,
|
|
42
|
+
accessKeySecret: process.env.GENAUTH_ACCESS_KEY_SECRET!,
|
|
43
|
+
userPoolId: process.env.GENAUTH_USER_POOL_ID!,
|
|
44
|
+
})
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Agent 与资源
|
|
48
|
+
|
|
49
|
+
### 创建 Agent
|
|
50
|
+
|
|
51
|
+
方法:`admin.personas.create`
|
|
52
|
+
|
|
53
|
+
创建通信资源所属的 Agent。已有 Agent 时直接使用它的 `personaId`。
|
|
54
|
+
|
|
55
|
+
| 参数 | 必填 | 说明 |
|
|
56
|
+
| --- | --- | --- |
|
|
57
|
+
| `displayName` | 是 | 显示名称 |
|
|
58
|
+
| `externalRef` | 否 | 业务系统中的关联标识 |
|
|
59
|
+
| `avatar` | 否 | 头像地址 |
|
|
60
|
+
|
|
61
|
+
返回 `data`:Agent 对象,包含 `personaId`、`displayName`、`status`、`revision`。
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
const { data: persona } = await qoni.genauth.agentMail.admin.personas.create({
|
|
65
|
+
displayName: 'Communication assistant',
|
|
66
|
+
externalRef: 'business-agent-001',
|
|
67
|
+
})
|
|
68
|
+
const personaId = persona.personaId
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
一个 Agent 可以拥有多个邮箱和手机号。Mail / Phone 调用传 `personaId`;身份委托调用传 `capabilities.identity.iamAgentId`。
|
|
72
|
+
|
|
73
|
+
### 查询资源
|
|
74
|
+
|
|
75
|
+
方法:`resources.list`
|
|
76
|
+
|
|
77
|
+
查看 Agent 名下的邮箱及登记的号码。
|
|
78
|
+
|
|
79
|
+
| 参数 | 必填 | 说明 |
|
|
80
|
+
| --- | --- | --- |
|
|
81
|
+
| `personaId` | 是 | Agent ID |
|
|
82
|
+
| `cursor / limit` | 否 | 分页游标与每页数量 |
|
|
83
|
+
|
|
84
|
+
返回 `data`:`{ items, nextCursor }`。每项包含 `resourceId`、`type`、`address`、`source`、`status`。
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
const { data: resources } = await qoni.genauth.agentMail.resources.list({
|
|
88
|
+
personaId,
|
|
89
|
+
limit: 20,
|
|
90
|
+
})
|
|
91
|
+
console.log(resources.items)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`type` 为 `email` 或 `phone`。号码采购、短信和租约操作使用 `agentPhone`。
|
|
95
|
+
|
|
96
|
+
## Agent Mail:邮箱与邮件
|
|
97
|
+
|
|
98
|
+
### 查询邮箱供应商
|
|
99
|
+
|
|
100
|
+
方法:`providers.list`
|
|
101
|
+
|
|
102
|
+
查询可用于创建邮箱、收信或发信的供应商配置。
|
|
103
|
+
|
|
104
|
+
| 参数 | 必填 | 说明 |
|
|
105
|
+
| --- | --- | --- |
|
|
106
|
+
| `capability` | 否 | 按能力筛选,例如 mailbox.create |
|
|
107
|
+
| `cursor / limit` | 否 | 分页游标与每页数量 |
|
|
108
|
+
|
|
109
|
+
返回 `data`:`{ items, nextCursor }`。配置包含 `configId`、`capabilities`、`allowedDomains`、`defaultDomain`、`acceptNewMailboxes`。
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
const { data: mailProviders } = await qoni.genauth.agentMail.providers.list({
|
|
113
|
+
capability: 'mailbox.create',
|
|
114
|
+
limit: 20,
|
|
115
|
+
})
|
|
116
|
+
const mailProvider = mailProviders.items.find(item => item.acceptNewMailboxes)
|
|
117
|
+
if (!mailProvider) throw new Error('No mailbox provider available')
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 创建邮箱
|
|
121
|
+
|
|
122
|
+
方法:`mailboxes.create`
|
|
123
|
+
|
|
124
|
+
为 Agent 创建一个邮箱。保存返回的操作 ID,随后等待创建完成。
|
|
125
|
+
|
|
126
|
+
| 参数 | 必填 | 说明 |
|
|
127
|
+
| --- | --- | --- |
|
|
128
|
+
| `personaId` | 是 | Agent ID |
|
|
129
|
+
| `idempotencyKey` | 是 | 本次创建命令的唯一键;重试复用原键 |
|
|
130
|
+
| `providerConfigId` | 否 | 供应商配置 ID |
|
|
131
|
+
| `localPart / domain / displayName` | 否 | 邮箱前缀、域名和显示名称 |
|
|
132
|
+
|
|
133
|
+
返回 `data`:`{ operationId, resourceId, status, pollAfterSeconds }`。`resourceId` 用作后续的 `mailboxId`。
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
const { data: mailboxRequest } = await qoni.genauth.agentMail.mailboxes.create({
|
|
137
|
+
personaId,
|
|
138
|
+
providerConfigId: mailProvider.configId,
|
|
139
|
+
displayName: 'Business assistant',
|
|
140
|
+
idempotencyKey: 'mailbox-create-business-001',
|
|
141
|
+
})
|
|
142
|
+
const mailboxId = mailboxRequest.resourceId
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
请求接受后返回 HTTP `202`,此时邮箱可能仍在创建。省略供应商时,仅有唯一可用配置才会自动选择;指定域名需在配置的允许范围内。
|
|
146
|
+
|
|
147
|
+
### 查询与等待操作
|
|
148
|
+
|
|
149
|
+
方法:`operations.get` / `operations.wait`
|
|
150
|
+
|
|
151
|
+
查询邮箱创建或邮件发送的进度。`get` 查询一次;`wait` 轮询到最终状态或超时。
|
|
152
|
+
|
|
153
|
+
| 参数 | 必填 | 说明 |
|
|
154
|
+
| --- | --- | --- |
|
|
155
|
+
| `operationId` | 是 | 创建或发送接口返回的操作 ID |
|
|
156
|
+
| `第二参数` | 否 | wait 可传 timeoutMs、pollIntervalMs、signal |
|
|
157
|
+
|
|
158
|
+
返回 `data`:操作对象,包含 `status`、`result`、`error`。状态为 `pending`、`running`、`succeeded`、`failed` 或 `unknown`。
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
const { data: mailboxProgress } = await qoni.genauth.agentMail.operations.get({
|
|
162
|
+
operationId: mailboxRequest.operationId,
|
|
163
|
+
})
|
|
164
|
+
const { data: mailboxOperation } = await qoni.genauth.agentMail.operations.wait({
|
|
165
|
+
operationId: mailboxRequest.operationId,
|
|
166
|
+
}, { timeoutMs: 120_000 })
|
|
167
|
+
if (mailboxOperation.status !== 'succeeded') {
|
|
168
|
+
throw new Error(`Mailbox operation: ${mailboxOperation.status}`)
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
`unknown` 时继续查询原操作或通过管理侧对账,不要换幂等键再次创建或发送。等待超时不会取消服务端操作。
|
|
173
|
+
|
|
174
|
+
### 读取邮箱
|
|
175
|
+
|
|
176
|
+
方法:`mailboxes.get`
|
|
177
|
+
|
|
178
|
+
读取邮箱地址、状态与可用能力。
|
|
179
|
+
|
|
180
|
+
| 参数 | 必填 | 说明 |
|
|
181
|
+
| --- | --- | --- |
|
|
182
|
+
| `personaId` | 是 | Agent ID |
|
|
183
|
+
| `mailboxId` | 是 | 邮箱资源 ID |
|
|
184
|
+
|
|
185
|
+
返回 `data`:邮箱对象,包含 `mailboxId`、`address`、`status`、`capabilities`、`revision`。
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
const { data: mailbox } = await qoni.genauth.agentMail.mailboxes.get({
|
|
189
|
+
personaId,
|
|
190
|
+
mailboxId,
|
|
191
|
+
})
|
|
192
|
+
if (mailbox.status === 'active') console.log(mailbox.address)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
创建中的邮箱 `address` 可以为空;使用邮箱前确认 `status` 为 `active`。
|
|
196
|
+
|
|
197
|
+
### 查询邮件
|
|
198
|
+
|
|
199
|
+
方法:`messages.list`
|
|
200
|
+
|
|
201
|
+
按方向和时间范围查询邮件摘要。
|
|
202
|
+
|
|
203
|
+
| 参数 | 必填 | 说明 |
|
|
204
|
+
| --- | --- | --- |
|
|
205
|
+
| `personaId / mailboxId` | 是 | Agent ID 与邮箱 ID |
|
|
206
|
+
| `direction` | 否 | inbound 收信;outbound 发信 |
|
|
207
|
+
| `after / before` | 否 | ISO 格式的时间边界 |
|
|
208
|
+
| `cursor / limit` | 否 | 分页游标;每页 1–100 条 |
|
|
209
|
+
|
|
210
|
+
返回 `data`:`{ items, nextCursor }`。摘要包含 `messageId`、`from`、`to`、`subject`、`contentStatus`、`deliveryStatus`。
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
const { data: mailMessages } = await qoni.genauth.agentMail.messages.list({
|
|
214
|
+
personaId,
|
|
215
|
+
mailboxId,
|
|
216
|
+
direction: 'inbound',
|
|
217
|
+
limit: 20,
|
|
218
|
+
})
|
|
219
|
+
console.log(mailMessages.items, mailMessages.nextCursor)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
下一页把 `nextCursor` 传入 `cursor`。列表不包含正文。
|
|
223
|
+
|
|
224
|
+
### 读取邮件正文
|
|
225
|
+
|
|
226
|
+
方法:`messages.get`
|
|
227
|
+
|
|
228
|
+
根据邮件 ID 读取主题、正文和投递状态。
|
|
229
|
+
|
|
230
|
+
| 参数 | 必填 | 说明 |
|
|
231
|
+
| --- | --- | --- |
|
|
232
|
+
| `personaId / mailboxId / messageId` | 是 | Agent、邮箱和邮件 ID |
|
|
233
|
+
|
|
234
|
+
返回 `data`:邮件详情,包含摘要字段与 `text`。`contentStatus` 为 `available` 时正文可读。
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
const { data: mailMessage } = await qoni.genauth.agentMail.messages.get({
|
|
238
|
+
personaId,
|
|
239
|
+
mailboxId,
|
|
240
|
+
messageId: 'message-id',
|
|
241
|
+
})
|
|
242
|
+
if (mailMessage.contentStatus === 'available') console.log(mailMessage.text)
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
正文状态为 `pending` 时稍后再查;`expired` 或 `unavailable` 时正文可能为空。
|
|
246
|
+
|
|
247
|
+
### 发送邮件
|
|
248
|
+
|
|
249
|
+
方法:`messages.send`
|
|
250
|
+
|
|
251
|
+
从 Agent 邮箱发送一封文本邮件。
|
|
252
|
+
|
|
253
|
+
| 参数 | 必填 | 说明 |
|
|
254
|
+
| --- | --- | --- |
|
|
255
|
+
| `personaId / mailboxId` | 是 | 发件 Agent 与邮箱 ID |
|
|
256
|
+
| `to / subject / text` | 是 | 单个收件地址、主题和正文 |
|
|
257
|
+
| `idempotencyKey` | 是 | 本次发送命令的唯一键 |
|
|
258
|
+
| `externalRef` | 否 | 业务关联标识 |
|
|
259
|
+
|
|
260
|
+
返回 `data`:异步操作 `{ operationId, resourceId, messageId?, status, pollAfterSeconds }`。
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
const { data: sendRequest } = await qoni.genauth.agentMail.messages.send({
|
|
264
|
+
personaId,
|
|
265
|
+
mailboxId,
|
|
266
|
+
to: 'recipient@example.com',
|
|
267
|
+
subject: 'Business notification',
|
|
268
|
+
text: 'Your request is complete.',
|
|
269
|
+
idempotencyKey: 'mail-send-business-001',
|
|
270
|
+
})
|
|
271
|
+
const { data: sendOperation } = await qoni.genauth.agentMail.operations.wait({
|
|
272
|
+
operationId: sendRequest.operationId,
|
|
273
|
+
})
|
|
274
|
+
console.log(sendOperation.status, sendOperation.result?.deliveryStatus)
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
邮箱需具有发送能力。`succeeded` 表示供应商接受了请求;投递状态查看 `deliveryStatus`,例如 `delivered`、`bounced` 或 `rejected`。
|
|
278
|
+
|
|
279
|
+
## Agent Mail:验证码与外部账号
|
|
280
|
+
|
|
281
|
+
### 创建验证码任务
|
|
282
|
+
|
|
283
|
+
方法:`verifications.create`
|
|
284
|
+
|
|
285
|
+
创建邮件匹配与验证码提取任务,再触发目标平台发送验证码。
|
|
286
|
+
|
|
287
|
+
| 参数 | 必填 | 说明 |
|
|
288
|
+
| --- | --- | --- |
|
|
289
|
+
| `personaId / mailboxId` | 是 | Agent 与邮箱 ID |
|
|
290
|
+
| `platformKey / externalRef` | 是 | 目标平台标识与本次业务流程标识 |
|
|
291
|
+
| `idempotencyKey` | 是 | 本次任务的唯一键 |
|
|
292
|
+
| `templateId` | 否 | 已配置模板 ID;与 match / extract 互斥 |
|
|
293
|
+
| `match / extract` | 否 | 不用模板时必填:匹配条件与提取规则 |
|
|
294
|
+
| `timeoutSeconds` | 否 | 30–600 秒,默认 180 秒 |
|
|
295
|
+
|
|
296
|
+
返回 `data`:任务对象,包含 `verificationRequestId`、`status`、`windowStart`、`expiresAt`、`result`。
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
const { data: mailVerification } = await qoni.genauth.agentMail.verifications.create({
|
|
300
|
+
personaId,
|
|
301
|
+
mailboxId,
|
|
302
|
+
platformKey: 'demo-platform',
|
|
303
|
+
externalRef: 'registration-attempt-001',
|
|
304
|
+
match: { fromDomains: ['demo.example.com'], subjectContains: 'Verification code' },
|
|
305
|
+
extract: { kind: 'code', pattern: 'Verification code[: ]*([0-9]{6})' },
|
|
306
|
+
timeoutSeconds: 180,
|
|
307
|
+
idempotencyKey: 'mail-verification-business-001',
|
|
308
|
+
})
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
`match` 至少指定 `fromAddresses` 或 `fromDomains`;正则需一个捕获组。提取链接时使用 `kind: 'link'` 并设置 `allowedLinkDomains`。任务只匹配本次时间窗口中的邮件。
|
|
312
|
+
|
|
313
|
+
### 读取与等待验证码
|
|
314
|
+
|
|
315
|
+
方法:`verifications.get` / `verifications.wait`
|
|
316
|
+
|
|
317
|
+
读取提取任务,或等待验证码、链接到达。
|
|
318
|
+
|
|
319
|
+
| 参数 | 必填 | 说明 |
|
|
320
|
+
| --- | --- | --- |
|
|
321
|
+
| `personaId / mailboxId / verificationRequestId` | 是 | Agent、邮箱与验证码任务 ID |
|
|
322
|
+
| `第二参数` | 否 | wait 的 timeoutMs、pollIntervalMs、signal |
|
|
323
|
+
|
|
324
|
+
返回 `data`:任务对象。`matched` 时 `result` 包含 `kind`、`value`、`messageId`;有效期见 `resultAvailableUntil`。
|
|
325
|
+
|
|
326
|
+
```ts
|
|
327
|
+
// Trigger the target platform to send its verification email before waiting.
|
|
328
|
+
const { data: mailVerificationProgress } = await qoni.genauth.agentMail.verifications.get({
|
|
329
|
+
personaId,
|
|
330
|
+
mailboxId,
|
|
331
|
+
verificationRequestId: mailVerification.verificationRequestId,
|
|
332
|
+
})
|
|
333
|
+
const { data: mailVerificationResult } = await qoni.genauth.agentMail.verifications.wait({
|
|
334
|
+
personaId,
|
|
335
|
+
mailboxId,
|
|
336
|
+
verificationRequestId: mailVerification.verificationRequestId,
|
|
337
|
+
}, { timeoutMs: 190_000 })
|
|
338
|
+
if (mailVerificationResult.status === 'matched') {
|
|
339
|
+
console.log(mailVerificationResult.result?.value)
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
`ambiguous` 表示匹配多个结果,需核对候选邮件;`expired` 表示任务超时。`resultExpired` 为 true 时不能继续使用旧结果。
|
|
344
|
+
|
|
345
|
+
### 取消邮件验证码任务
|
|
346
|
+
|
|
347
|
+
方法:`verifications.cancel`
|
|
348
|
+
|
|
349
|
+
取消不再需要的邮件提取任务。
|
|
350
|
+
|
|
351
|
+
| 参数 | 必填 | 说明 |
|
|
352
|
+
| --- | --- | --- |
|
|
353
|
+
| `personaId / mailboxId / verificationRequestId` | 是 | Agent、邮箱与任务 ID |
|
|
354
|
+
| `idempotencyKey` | 是 | 取消命令的唯一键 |
|
|
355
|
+
|
|
356
|
+
返回 `data`:验证码任务对象与当前 `status`。
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
const { data: cancelledMailVerification } = await qoni.genauth.agentMail.verifications.cancel({
|
|
360
|
+
personaId,
|
|
361
|
+
mailboxId,
|
|
362
|
+
verificationRequestId: 'mail-verification-to-cancel',
|
|
363
|
+
idempotencyKey: 'mail-verification-cancel-001',
|
|
364
|
+
})
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### 记录外部账号
|
|
368
|
+
|
|
369
|
+
方法:`externalAccounts.create`
|
|
370
|
+
|
|
371
|
+
记录 Agent 在外部平台注册的账号,以及邮箱或号码在注册、登录、找回中的用途。
|
|
372
|
+
|
|
373
|
+
| 参数 | 必填 | 说明 |
|
|
374
|
+
| --- | --- | --- |
|
|
375
|
+
| `personaId / platformKey / externalRef` | 是 | Agent、平台与业务关联标识 |
|
|
376
|
+
| `registrationResult` | 是 | registered 已注册;recorded 仅记录 |
|
|
377
|
+
| `platformAccountId / username / profileUrl` | 否 | 至少设置其中一个账号标识 |
|
|
378
|
+
| `bindings` | 否 | 资源 ID、purposes 与 isCurrent |
|
|
379
|
+
| `idempotencyKey` | 是 | 本次记录命令的唯一键 |
|
|
380
|
+
|
|
381
|
+
返回 `data`:账号对象,包含 `accountId`、`bindings`、`recordStatus`、`revision`。
|
|
382
|
+
|
|
383
|
+
```ts
|
|
384
|
+
const { data: externalAccount } = await qoni.genauth.agentMail.externalAccounts.create({
|
|
385
|
+
personaId,
|
|
386
|
+
platformKey: 'demo-platform',
|
|
387
|
+
externalRef: 'platform-account-001',
|
|
388
|
+
username: 'business-assistant',
|
|
389
|
+
registrationResult: 'registered',
|
|
390
|
+
bindings: [{ resourceId: mailboxId, purposes: ['registration', 'login'], isCurrent: true }],
|
|
391
|
+
idempotencyKey: 'external-account-create-001',
|
|
392
|
+
})
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
账号记录不存储密码。`purposes` 可选 `registration`、`login`、`recovery`、`contact`。
|
|
396
|
+
|
|
397
|
+
### 查询与更新外部账号
|
|
398
|
+
|
|
399
|
+
方法:`externalAccounts.list` / `get` / `update`
|
|
400
|
+
|
|
401
|
+
查询账号记录,更新资料或归档不再使用的账号。
|
|
402
|
+
|
|
403
|
+
| 参数 | 必填 | 说明 |
|
|
404
|
+
| --- | --- | --- |
|
|
405
|
+
| `personaId` | 是 | Agent ID |
|
|
406
|
+
| `accountId` | 否 | get / update 必填 |
|
|
407
|
+
| `revision` | 否 | update 必填;使用当前版本 |
|
|
408
|
+
| `recordStatus / bindings / notes` | 否 | 账号状态、资源绑定与备注 |
|
|
409
|
+
| `cursor / limit` | 否 | list 的分页参数 |
|
|
410
|
+
|
|
411
|
+
返回 `data`:list 返回 `{ items, nextCursor }`;get / update 返回账号对象。
|
|
412
|
+
|
|
413
|
+
```ts
|
|
414
|
+
const { data: externalAccounts } = await qoni.genauth.agentMail.externalAccounts.list({ personaId, limit: 20 })
|
|
415
|
+
const { data: accountDetails } = await qoni.genauth.agentMail.externalAccounts.get({
|
|
416
|
+
personaId, accountId: externalAccount.accountId,
|
|
417
|
+
})
|
|
418
|
+
const { data: updatedAccount } = await qoni.genauth.agentMail.externalAccounts.update({
|
|
419
|
+
personaId,
|
|
420
|
+
accountId: accountDetails.accountId,
|
|
421
|
+
revision: accountDetails.revision,
|
|
422
|
+
notes: 'Verified by business workflow',
|
|
423
|
+
})
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
## Agent Phone:号码与短信
|
|
427
|
+
|
|
428
|
+
### 查询供应商
|
|
429
|
+
|
|
430
|
+
方法:`admin.providers.list`
|
|
431
|
+
|
|
432
|
+
读取 Phone 供应商配置、启用状态与健康检查结果。
|
|
433
|
+
|
|
434
|
+
无业务参数。
|
|
435
|
+
|
|
436
|
+
返回 `data`:`{ items }`。包含 `id`、`provider`、`enabled`、`settings`、`health`、`revision`,不返回明文凭据。
|
|
437
|
+
|
|
438
|
+
```ts
|
|
439
|
+
const { data: phoneProviders } = await qoni.genauth.agentPhone.admin.providers.list()
|
|
440
|
+
const phoneProvider = phoneProviders.items.find(item => item.provider === 'twilio' && item.enabled)
|
|
441
|
+
if (!phoneProvider) throw new Error('No enabled Twilio provider')
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### 查询候选号码
|
|
445
|
+
|
|
446
|
+
方法:`candidates.list`
|
|
447
|
+
|
|
448
|
+
在采购长期号码前查询指定国家的可选号码及能力。
|
|
449
|
+
|
|
450
|
+
| 参数 | 必填 | 说明 |
|
|
451
|
+
| --- | --- | --- |
|
|
452
|
+
| `personaId / providerConfigId` | 是 | Agent 与供应商配置 ID |
|
|
453
|
+
| `country` | 是 | 国家代码,例如 US |
|
|
454
|
+
|
|
455
|
+
返回 `data`:`{ items }`,每项包含 `phone`、`country`、`numberType`、`smsReceive`、`smsSend`、`thirdPartyOtp`。
|
|
456
|
+
|
|
457
|
+
```ts
|
|
458
|
+
const { data: numberCandidates } = await qoni.genauth.agentPhone.candidates.list({
|
|
459
|
+
personaId,
|
|
460
|
+
providerConfigId: phoneProvider.id,
|
|
461
|
+
country: 'US',
|
|
462
|
+
})
|
|
463
|
+
console.log(numberCandidates.items)
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
能力字段是字符串状态,`unknown` 不表示支持。
|
|
467
|
+
|
|
468
|
+
### 获取报价
|
|
469
|
+
|
|
470
|
+
方法:`quotes.create`
|
|
471
|
+
|
|
472
|
+
取得长期号码或一次性接码的供应商报价。
|
|
473
|
+
|
|
474
|
+
| 参数 | 必填 | 说明 |
|
|
475
|
+
| --- | --- | --- |
|
|
476
|
+
| `personaId / providerConfigId` | 是 | Agent 与供应商配置 ID |
|
|
477
|
+
| `kind` | 是 | number 长期号码;activation 一次性接码 |
|
|
478
|
+
| `spec` | 是 | country;按报价类型传 phone 或 service |
|
|
479
|
+
|
|
480
|
+
返回 `data`:报价对象,包含 `id`、`kind`、`amount`、`currency`、`expiresAt`、`configRevision`。
|
|
481
|
+
|
|
482
|
+
```ts
|
|
483
|
+
const { data: numberQuote } = await qoni.genauth.agentPhone.quotes.create({
|
|
484
|
+
personaId,
|
|
485
|
+
providerConfigId: phoneProvider.id,
|
|
486
|
+
kind: 'number',
|
|
487
|
+
spec: { country: 'US' },
|
|
488
|
+
})
|
|
489
|
+
console.log(numberQuote.amount, numberQuote.currency, numberQuote.expiresAt)
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
报价有效期两分钟,绑定创建者与 Agent。过期后重新报价;金额是十进制字符串。
|
|
493
|
+
|
|
494
|
+
### 采购号码
|
|
495
|
+
|
|
496
|
+
方法:`numbers.acquire`
|
|
497
|
+
|
|
498
|
+
确认报价和费用上限后为 Agent 采购号码。
|
|
499
|
+
|
|
500
|
+
| 参数 | 必填 | 说明 |
|
|
501
|
+
| --- | --- | --- |
|
|
502
|
+
| `personaId / quoteId` | 是 | Agent 与 number 报价 ID |
|
|
503
|
+
| `maxCost` | 是 | { amount, currency };本次采购费用上限 |
|
|
504
|
+
| `idempotencyKey` | 是 | 采购命令的唯一键 |
|
|
505
|
+
|
|
506
|
+
返回 `data`:Phone 操作对象,`id` 为操作 ID;最终结果含资源关联信息。
|
|
507
|
+
|
|
508
|
+
```ts
|
|
509
|
+
const { data: acquisition } = await qoni.genauth.agentPhone.numbers.acquire({
|
|
510
|
+
personaId,
|
|
511
|
+
quoteId: numberQuote.id,
|
|
512
|
+
maxCost: { amount: numberQuote.amount, currency: numberQuote.currency },
|
|
513
|
+
idempotencyKey: 'phone-acquire-business-001',
|
|
514
|
+
})
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
采购会产生费用。币种必须与报价一致;`maxCost.amount` 使用最多六位小数的字符串。供应商、费用策略和采购开关需允许本次操作。
|
|
518
|
+
|
|
519
|
+
### 查询与等待号码操作
|
|
520
|
+
|
|
521
|
+
方法:`operations.get` / `operations.wait` / `operations.list`
|
|
522
|
+
|
|
523
|
+
查询采购、发送、释放或一次性接码操作的执行结果。
|
|
524
|
+
|
|
525
|
+
| 参数 | 必填 | 说明 |
|
|
526
|
+
| --- | --- | --- |
|
|
527
|
+
| `personaId` | 是 | Agent ID |
|
|
528
|
+
| `operationId` | 否 | get / wait 必填;操作对象的 id |
|
|
529
|
+
| `第二参数` | 否 | wait 的 timeoutMs、pollIntervalMs、signal |
|
|
530
|
+
|
|
531
|
+
返回 `data`:get / wait 返回操作对象,包含 `status`、`stage`、`resourceId`、`taskId`、`errorCode`、`cost`;list 返回 `{ items }`。
|
|
532
|
+
|
|
533
|
+
```ts
|
|
534
|
+
const { data: phoneOperation } = await qoni.genauth.agentPhone.operations.wait({
|
|
535
|
+
personaId,
|
|
536
|
+
operationId: acquisition.id,
|
|
537
|
+
}, { timeoutMs: 120_000 })
|
|
538
|
+
if (phoneOperation.status !== 'succeeded' || !phoneOperation.resourceId) {
|
|
539
|
+
throw new Error(`Phone operation: ${phoneOperation.status}`)
|
|
540
|
+
}
|
|
541
|
+
const resourceId = phoneOperation.resourceId
|
|
542
|
+
const { data: phoneProgress } = await qoni.genauth.agentPhone.operations.get({
|
|
543
|
+
personaId, operationId: acquisition.id,
|
|
544
|
+
})
|
|
545
|
+
const { data: phoneOperations } = await qoni.genauth.agentPhone.operations.list({ personaId })
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
Phone 操作 ID 字段为 `id`,Mail 为 `operationId`。遇到 `unknown` 时查询原操作;不要换键重新采购或发送。
|
|
549
|
+
|
|
550
|
+
### 查询号码
|
|
551
|
+
|
|
552
|
+
方法:`numbers.list` / `numbers.get`
|
|
553
|
+
|
|
554
|
+
读取 Agent 名下的号码、短信能力和租约。
|
|
555
|
+
|
|
556
|
+
| 参数 | 必填 | 说明 |
|
|
557
|
+
| --- | --- | --- |
|
|
558
|
+
| `personaId` | 是 | Agent ID |
|
|
559
|
+
| `resourceId` | 否 | get 必填;号码资源 ID |
|
|
560
|
+
| `q / state / page / limit` | 否 | list 的关键词、状态和分页参数 |
|
|
561
|
+
|
|
562
|
+
返回 `data`:list 返回 `{ items, total, page, limit }`;get 返回号码对象,包含 `phone`、`state`、`capabilities`、`lease`、`revision`。
|
|
563
|
+
|
|
564
|
+
```ts
|
|
565
|
+
const { data: numberPage } = await qoni.genauth.agentPhone.numbers.list({
|
|
566
|
+
personaId, page: 1, limit: 20,
|
|
567
|
+
})
|
|
568
|
+
const { data: phoneNumber } = await qoni.genauth.agentPhone.numbers.get({ personaId, resourceId })
|
|
569
|
+
console.log(phoneNumber.phone, phoneNumber.capabilities, phoneNumber.lease)
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
短信操作前检查 `smsReceive` / `smsSend`;第三方验证码检查 `thirdPartyOtp`。号码和租约还需处于可用状态。
|
|
573
|
+
|
|
574
|
+
### 查询短信
|
|
575
|
+
|
|
576
|
+
方法:`numbers.messages`
|
|
577
|
+
|
|
578
|
+
读取号码收到或发出的短信摘要。
|
|
579
|
+
|
|
580
|
+
| 参数 | 必填 | 说明 |
|
|
581
|
+
| --- | --- | --- |
|
|
582
|
+
| `personaId / resourceId` | 是 | Agent 与号码资源 ID |
|
|
583
|
+
|
|
584
|
+
返回 `data`:`{ items }`。摘要包含 `id`、`from`、`to`、`direction`、`status`、`contentAvailable`。
|
|
585
|
+
|
|
586
|
+
```ts
|
|
587
|
+
const { data: smsMessages } = await qoni.genauth.agentPhone.numbers.messages({ personaId, resourceId })
|
|
588
|
+
console.log(smsMessages.items)
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
列表没有正文。读取短信需要 `sms.read`;读取正文还需 `sms.content.read`。
|
|
592
|
+
|
|
593
|
+
### 读取短信正文
|
|
594
|
+
|
|
595
|
+
方法:`messages.content`
|
|
596
|
+
|
|
597
|
+
使用短信 ID 读取正文。
|
|
598
|
+
|
|
599
|
+
| 参数 | 必填 | 说明 |
|
|
600
|
+
| --- | --- | --- |
|
|
601
|
+
| `personaId / messageId` | 是 | Agent 与短信 ID;不是号码资源 ID |
|
|
602
|
+
|
|
603
|
+
返回 `data`:`{ body }`。
|
|
604
|
+
|
|
605
|
+
```ts
|
|
606
|
+
const { data: smsContent } = await qoni.genauth.agentPhone.messages.content({
|
|
607
|
+
personaId,
|
|
608
|
+
messageId: 'sms-message-id',
|
|
609
|
+
})
|
|
610
|
+
console.log(smsContent.body)
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
正文具有保留期限。`contentAvailable` 为 false 或返回 `CONTENT_EXPIRED` 时,不能继续读取旧正文。
|
|
614
|
+
|
|
615
|
+
### 发送短信
|
|
616
|
+
|
|
617
|
+
方法:`numbers.send`
|
|
618
|
+
|
|
619
|
+
使用 Agent 号码向目标号码发送短信。
|
|
620
|
+
|
|
621
|
+
| 参数 | 必填 | 说明 |
|
|
622
|
+
| --- | --- | --- |
|
|
623
|
+
| `personaId / resourceId` | 是 | Agent 与发件号码资源 ID |
|
|
624
|
+
| `to / body` | 是 | 目标号码与短信正文 |
|
|
625
|
+
| `maxCost` | 是 | 费用上限与币种 |
|
|
626
|
+
| `idempotencyKey` | 是 | 发送命令的唯一键 |
|
|
627
|
+
|
|
628
|
+
返回 `data`:Phone 操作对象。使用 `operations.wait` 查询执行结果。
|
|
629
|
+
|
|
630
|
+
```ts
|
|
631
|
+
const { data: smsSendOperation } = await qoni.genauth.agentPhone.numbers.send({
|
|
632
|
+
personaId,
|
|
633
|
+
resourceId,
|
|
634
|
+
to: '+12025550123',
|
|
635
|
+
body: 'Your request is complete.',
|
|
636
|
+
maxCost: { amount: '0.050000', currency: 'USD' },
|
|
637
|
+
idempotencyKey: 'sms-send-business-001',
|
|
638
|
+
})
|
|
639
|
+
const { data: smsSendResult } = await qoni.genauth.agentPhone.operations.wait({
|
|
640
|
+
personaId, operationId: smsSendOperation.id,
|
|
641
|
+
})
|
|
642
|
+
console.log(smsSendResult.status)
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
发送会产生费用。根据供应商计价与业务预算设置 `maxCost`,并确认号码具备发送能力。
|
|
646
|
+
|
|
647
|
+
### 释放号码
|
|
648
|
+
|
|
649
|
+
方法:`numbers.release`
|
|
650
|
+
|
|
651
|
+
向供应商提交号码释放请求。释放前先处理外部账号中的登录、找回和联系绑定。
|
|
652
|
+
|
|
653
|
+
| 参数 | 必填 | 说明 |
|
|
654
|
+
| --- | --- | --- |
|
|
655
|
+
| `personaId / resourceId` | 是 | Agent 与号码资源 ID |
|
|
656
|
+
| `reason` | 是 | 释放原因 |
|
|
657
|
+
| `revision` | 是 | numbers.get 返回的当前版本 |
|
|
658
|
+
| `idempotencyKey` | 是 | 释放命令的唯一键 |
|
|
659
|
+
|
|
660
|
+
返回 `data`:异步释放操作;随后使用 `operations.wait` 和 `numbers.get` 核对状态。
|
|
661
|
+
|
|
662
|
+
```ts
|
|
663
|
+
const { data: releaseOperation } = await qoni.genauth.agentPhone.numbers.release({
|
|
664
|
+
personaId,
|
|
665
|
+
resourceId,
|
|
666
|
+
reason: 'Business workflow completed',
|
|
667
|
+
revision: phoneNumber.revision,
|
|
668
|
+
idempotencyKey: 'phone-release-business-001',
|
|
669
|
+
})
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
使用最新版本;冲突返回 `412` 时重新读取号码。采购与释放示例属于不同业务操作,按实际流程调用。
|
|
673
|
+
|
|
674
|
+
## Agent Phone:验证码
|
|
675
|
+
|
|
676
|
+
### 创建验证码任务
|
|
677
|
+
|
|
678
|
+
方法:`verifications.create`
|
|
679
|
+
|
|
680
|
+
为已有号码建立验证码接收任务,再触发目标平台发送短信。
|
|
681
|
+
|
|
682
|
+
| 参数 | 必填 | 说明 |
|
|
683
|
+
| --- | --- | --- |
|
|
684
|
+
| `personaId / resourceId` | 是 | Agent 与已有号码资源 ID |
|
|
685
|
+
| `service` | 是 | 目标业务或平台标识 |
|
|
686
|
+
| `rules` | 是 | { pattern, sender? },验证码提取规则 |
|
|
687
|
+
| `timeoutSeconds` | 否 | 任务等待期限,30–900 秒 |
|
|
688
|
+
|
|
689
|
+
返回 `data`:任务对象,包含 `id`、`status`、`expiresAt`、`candidateIds`、`revision`。
|
|
690
|
+
|
|
691
|
+
```ts
|
|
692
|
+
const { data: phoneVerification } = await qoni.genauth.agentPhone.verifications.create({
|
|
693
|
+
personaId,
|
|
694
|
+
resourceId,
|
|
695
|
+
service: 'demo-platform',
|
|
696
|
+
rules: { pattern: 'Code[: ]*([0-9]{6})' },
|
|
697
|
+
timeoutSeconds: 180,
|
|
698
|
+
})
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
### 查询与等待验证码
|
|
702
|
+
|
|
703
|
+
方法:`verifications.list` / `get` / `wait`
|
|
704
|
+
|
|
705
|
+
查询任务进度或等待验证码到达。
|
|
706
|
+
|
|
707
|
+
| 参数 | 必填 | 说明 |
|
|
708
|
+
| --- | --- | --- |
|
|
709
|
+
| `personaId` | 是 | Agent ID |
|
|
710
|
+
| `taskId` | 否 | get / wait 必填;创建任务返回的 id |
|
|
711
|
+
| `resourceId` | 否 | list 按号码筛选 |
|
|
712
|
+
| `第二参数` | 否 | wait 的 timeoutMs、pollIntervalMs、signal |
|
|
713
|
+
|
|
714
|
+
返回 `data`:list 返回 `{ items }`;get / wait 返回任务对象。
|
|
715
|
+
|
|
716
|
+
```ts
|
|
717
|
+
const { data: verificationList } = await qoni.genauth.agentPhone.verifications.list({ personaId, resourceId })
|
|
718
|
+
const { data: verificationProgress } = await qoni.genauth.agentPhone.verifications.get({
|
|
719
|
+
personaId, taskId: phoneVerification.id,
|
|
720
|
+
})
|
|
721
|
+
// Trigger the target platform to send its SMS before waiting.
|
|
722
|
+
const { data: readyVerification } = await qoni.genauth.agentPhone.verifications.wait({
|
|
723
|
+
personaId, taskId: phoneVerification.id,
|
|
724
|
+
}, { timeoutMs: 190_000 })
|
|
725
|
+
console.log(readyVerification.status)
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
`wait` 只轮询 `waiting` 状态。`ready` 后读取候选并消费;`ambiguous` 时需显式选择候选。
|
|
729
|
+
|
|
730
|
+
### 读取候选验证码
|
|
731
|
+
|
|
732
|
+
方法:`verifications.candidates`
|
|
733
|
+
|
|
734
|
+
获取任务匹配到的验证码及候选 ID。
|
|
735
|
+
|
|
736
|
+
| 参数 | 必填 | 说明 |
|
|
737
|
+
| --- | --- | --- |
|
|
738
|
+
| `personaId / taskId` | 是 | Agent 与验证码任务 ID |
|
|
739
|
+
|
|
740
|
+
返回 `data`:`{ items, expiresAt }`,候选包含 `candidateId` 与 `value`。
|
|
741
|
+
|
|
742
|
+
```ts
|
|
743
|
+
const { data: verificationCandidates } = await qoni.genauth.agentPhone.verifications.candidates({
|
|
744
|
+
personaId, taskId: phoneVerification.id,
|
|
745
|
+
})
|
|
746
|
+
console.log(verificationCandidates.items, verificationCandidates.expiresAt)
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
读取候选还需要 `sms.content.read` 权限。多候选时先按业务上下文核对,不能直接取第一条。
|
|
750
|
+
|
|
751
|
+
### 消费验证码
|
|
752
|
+
|
|
753
|
+
方法:`verifications.consume`
|
|
754
|
+
|
|
755
|
+
确认使用一个验证码结果。
|
|
756
|
+
|
|
757
|
+
| 参数 | 必填 | 说明 |
|
|
758
|
+
| --- | --- | --- |
|
|
759
|
+
| `personaId / taskId` | 是 | Agent 与验证码任务 ID |
|
|
760
|
+
| `idempotencyKey` | 是 | 本次消费命令的唯一键 |
|
|
761
|
+
| `candidateId` | 否 | 多候选时必填;使用已核对的候选 ID |
|
|
762
|
+
|
|
763
|
+
返回 `data`:结果对象,包含 `candidateId`、`value` 及关联信息。
|
|
764
|
+
|
|
765
|
+
```ts
|
|
766
|
+
const { data: consumedVerification } = await qoni.genauth.agentPhone.verifications.consume({
|
|
767
|
+
personaId,
|
|
768
|
+
taskId: phoneVerification.id,
|
|
769
|
+
candidateId: 'verified-candidate-id',
|
|
770
|
+
idempotencyKey: 'phone-verification-consume-001',
|
|
771
|
+
})
|
|
772
|
+
console.log(consumedVerification.value)
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
已消费、过期、撤销或租约发生变化的结果不可再次用于新的业务命令。重试原命令复用原幂等键。
|
|
776
|
+
|
|
777
|
+
### 取消验证码任务
|
|
778
|
+
|
|
779
|
+
方法:`verifications.cancel`
|
|
780
|
+
|
|
781
|
+
撤销不再需要的验证码任务。
|
|
782
|
+
|
|
783
|
+
| 参数 | 必填 | 说明 |
|
|
784
|
+
| --- | --- | --- |
|
|
785
|
+
| `personaId / taskId` | 是 | Agent 与任务 ID |
|
|
786
|
+
| `revision` | 是 | 任务的当前版本 |
|
|
787
|
+
| `idempotencyKey` | 是 | 取消命令的唯一键 |
|
|
788
|
+
|
|
789
|
+
返回 `data`:`{ id, status: 'revoked' }`。
|
|
790
|
+
|
|
791
|
+
```ts
|
|
792
|
+
const { data: cancelTarget } = await qoni.genauth.agentPhone.verifications.get({
|
|
793
|
+
personaId, taskId: 'verification-to-cancel',
|
|
794
|
+
})
|
|
795
|
+
const { data: cancelledVerification } = await qoni.genauth.agentPhone.verifications.cancel({
|
|
796
|
+
personaId,
|
|
797
|
+
taskId: cancelTarget.id,
|
|
798
|
+
revision: cancelTarget.revision,
|
|
799
|
+
idempotencyKey: 'phone-verification-cancel-001',
|
|
800
|
+
})
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
## Agent Phone:一次性接码
|
|
804
|
+
|
|
805
|
+
### 查询接码服务
|
|
806
|
+
|
|
807
|
+
方法:`catalog.list`
|
|
808
|
+
|
|
809
|
+
查询供应商在指定国家支持的平台、库存和报价。
|
|
810
|
+
|
|
811
|
+
| 参数 | 必填 | 说明 |
|
|
812
|
+
| --- | --- | --- |
|
|
813
|
+
| `personaId / providerConfigId / country` | 是 | Agent、供应商配置与国家代码 |
|
|
814
|
+
|
|
815
|
+
返回 `data`:`{ items }`。每项包含 `service` 与 `offers`;offer 包含 `operator`、`count`、`amount`、`currency`。
|
|
816
|
+
|
|
817
|
+
```ts
|
|
818
|
+
const { data: activationProviders } = await qoni.genauth.agentPhone.admin.providers.list()
|
|
819
|
+
const activationProvider = activationProviders.items.find(item => item.provider === '5sim' && item.enabled)
|
|
820
|
+
if (!activationProvider) throw new Error('No enabled activation provider')
|
|
821
|
+
const { data: activationCatalog } = await qoni.genauth.agentPhone.catalog.list({
|
|
822
|
+
personaId, providerConfigId: activationProvider.id, country: 'US',
|
|
823
|
+
})
|
|
824
|
+
console.log(activationCatalog.items)
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
### 创建接码任务
|
|
828
|
+
|
|
829
|
+
方法:`activations.create`
|
|
830
|
+
|
|
831
|
+
取得 activation 报价后采购一次性接码。
|
|
832
|
+
|
|
833
|
+
| 参数 | 必填 | 说明 |
|
|
834
|
+
| --- | --- | --- |
|
|
835
|
+
| `personaId / quoteId` | 是 | Agent 与 activation 报价 ID |
|
|
836
|
+
| `maxCost` | 是 | 费用上限与报价币种 |
|
|
837
|
+
| `idempotencyKey` | 是 | 本次接码采购的唯一键 |
|
|
838
|
+
|
|
839
|
+
返回 `data`:Phone 操作对象。操作完成后用 `taskId` 读取接码任务。
|
|
840
|
+
|
|
841
|
+
```ts
|
|
842
|
+
const { data: activationQuote } = await qoni.genauth.agentPhone.quotes.create({
|
|
843
|
+
personaId,
|
|
844
|
+
providerConfigId: activationProvider.id,
|
|
845
|
+
kind: 'activation',
|
|
846
|
+
spec: { country: 'US', service: 'service-from-catalog' },
|
|
847
|
+
})
|
|
848
|
+
const { data: activationPurchase } = await qoni.genauth.agentPhone.activations.create({
|
|
849
|
+
personaId,
|
|
850
|
+
quoteId: activationQuote.id,
|
|
851
|
+
maxCost: { amount: activationQuote.amount, currency: activationQuote.currency },
|
|
852
|
+
idempotencyKey: 'activation-create-business-001',
|
|
853
|
+
})
|
|
854
|
+
const { data: activationOperation } = await qoni.genauth.agentPhone.operations.wait({
|
|
855
|
+
personaId, operationId: activationPurchase.id,
|
|
856
|
+
})
|
|
857
|
+
if (activationOperation.status !== 'succeeded' || !activationOperation.taskId) {
|
|
858
|
+
throw new Error(`Activation operation: ${activationOperation.status}`)
|
|
859
|
+
}
|
|
860
|
+
const activationTaskId = activationOperation.taskId
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
`service` 必须使用目录中的实际值。接码会产生费用;任务号码只在其有效期和指定业务范围内使用。
|
|
864
|
+
|
|
865
|
+
### 查询接码任务
|
|
866
|
+
|
|
867
|
+
方法:`activations.list` / `activations.get`
|
|
868
|
+
|
|
869
|
+
查询临时号码、任务进度、结果与费用状态。
|
|
870
|
+
|
|
871
|
+
| 参数 | 必填 | 说明 |
|
|
872
|
+
| --- | --- | --- |
|
|
873
|
+
| `personaId` | 是 | Agent ID |
|
|
874
|
+
| `taskId` | 否 | get 必填;接码任务 ID |
|
|
875
|
+
|
|
876
|
+
返回 `data`:list 返回 `{ items }`;get 返回任务对象,含 `phone`、`status`、`resultState`、`costState`、`expiresAt`、`revision`。
|
|
877
|
+
|
|
878
|
+
```ts
|
|
879
|
+
const { data: activations } = await qoni.genauth.agentPhone.activations.list({ personaId })
|
|
880
|
+
const { data: activation } = await qoni.genauth.agentPhone.activations.get({
|
|
881
|
+
personaId, taskId: activationTaskId,
|
|
882
|
+
})
|
|
883
|
+
console.log(activation.phone, activation.status, activation.expiresAt)
|
|
884
|
+
```
|
|
885
|
+
|
|
886
|
+
取得可用号码后再触发外部平台发送验证码。采购操作完成不代表验证码已经收到。
|
|
887
|
+
|
|
888
|
+
### 查询接码短信
|
|
889
|
+
|
|
890
|
+
方法:`activations.messages`
|
|
891
|
+
|
|
892
|
+
查看接码任务收到的短信摘要。
|
|
893
|
+
|
|
894
|
+
| 参数 | 必填 | 说明 |
|
|
895
|
+
| --- | --- | --- |
|
|
896
|
+
| `personaId / taskId` | 是 | Agent 与接码任务 ID |
|
|
897
|
+
|
|
898
|
+
返回 `data`:`{ items }`,摘要字段与 `numbers.messages` 相同。
|
|
899
|
+
|
|
900
|
+
```ts
|
|
901
|
+
const { data: activationMessages } = await qoni.genauth.agentPhone.activations.messages({
|
|
902
|
+
personaId, taskId: activationTaskId,
|
|
903
|
+
})
|
|
904
|
+
console.log(activationMessages.items)
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
正文用 `messages.content` 读取;列表中的 `id` 是短信 ID。
|
|
908
|
+
|
|
909
|
+
### 查询候选结果
|
|
910
|
+
|
|
911
|
+
方法:`activations.candidates`
|
|
912
|
+
|
|
913
|
+
读取接码任务的候选验证码。
|
|
914
|
+
|
|
915
|
+
| 参数 | 必填 | 说明 |
|
|
916
|
+
| --- | --- | --- |
|
|
917
|
+
| `personaId / taskId` | 是 | Agent 与接码任务 ID |
|
|
918
|
+
|
|
919
|
+
返回 `data`:`{ items, expiresAt }`,每个结果包含 `candidateId` 与 `value`。
|
|
920
|
+
|
|
921
|
+
```ts
|
|
922
|
+
const { data: activationCandidates } = await qoni.genauth.agentPhone.activations.candidates({
|
|
923
|
+
personaId, taskId: activationTaskId,
|
|
924
|
+
})
|
|
925
|
+
console.log(activationCandidates.items)
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
未收到结果时按业务等待期限再次查询。多个候选时核对目标业务后显式选择,不要自动取第一条。
|
|
929
|
+
|
|
930
|
+
### 消费接码结果
|
|
931
|
+
|
|
932
|
+
方法:`activations.consume`
|
|
933
|
+
|
|
934
|
+
确认使用一个接码结果。
|
|
935
|
+
|
|
936
|
+
| 参数 | 必填 | 说明 |
|
|
937
|
+
| --- | --- | --- |
|
|
938
|
+
| `personaId / taskId / idempotencyKey` | 是 | Agent、任务 ID 与本次消费的唯一键 |
|
|
939
|
+
| `candidateId` | 否 | 多候选时必填;已核对的候选 ID |
|
|
940
|
+
|
|
941
|
+
返回 `data`:结果对象,包含 `candidateId`、`value` 及关联信息。
|
|
942
|
+
|
|
943
|
+
```ts
|
|
944
|
+
const { data: activationResult } = await qoni.genauth.agentPhone.activations.consume({
|
|
945
|
+
personaId,
|
|
946
|
+
taskId: activationTaskId,
|
|
947
|
+
candidateId: 'verified-activation-candidate-id',
|
|
948
|
+
idempotencyKey: 'activation-consume-business-001',
|
|
949
|
+
})
|
|
950
|
+
console.log(activationResult.value)
|
|
951
|
+
```
|
|
952
|
+
|
|
953
|
+
消费与结束任务是两个操作。消费结果后按实际业务决定是否调用 `finish`。
|
|
954
|
+
|
|
955
|
+
### 取消接码
|
|
956
|
+
|
|
957
|
+
方法:`activations.cancel`
|
|
958
|
+
|
|
959
|
+
向供应商提交取消接码请求。
|
|
960
|
+
|
|
961
|
+
| 参数 | 必填 | 说明 |
|
|
962
|
+
| --- | --- | --- |
|
|
963
|
+
| `personaId / taskId` | 是 | Agent 与接码任务 ID |
|
|
964
|
+
| `revision / idempotencyKey` | 是 | 当前任务版本与取消命令唯一键 |
|
|
965
|
+
|
|
966
|
+
返回 `data`:Phone 操作对象,随后通过 `operations.wait` 查询结果。
|
|
967
|
+
|
|
968
|
+
```ts
|
|
969
|
+
const { data: activationToCancel } = await qoni.genauth.agentPhone.activations.get({
|
|
970
|
+
personaId, taskId: 'activation-to-cancel',
|
|
971
|
+
})
|
|
972
|
+
const { data: activationCancellation } = await qoni.genauth.agentPhone.activations.cancel({
|
|
973
|
+
personaId,
|
|
974
|
+
taskId: activationToCancel.id,
|
|
975
|
+
revision: activationToCancel.revision,
|
|
976
|
+
idempotencyKey: 'activation-cancel-business-001',
|
|
977
|
+
})
|
|
978
|
+
```
|
|
979
|
+
|
|
980
|
+
是否可以取消、如何结算由供应商和任务当前状态决定;提交取消不等于退款成功。
|
|
981
|
+
|
|
982
|
+
### 结束接码
|
|
983
|
+
|
|
984
|
+
方法:`activations.finish`
|
|
985
|
+
|
|
986
|
+
业务完成后向供应商提交结束任务请求。
|
|
987
|
+
|
|
988
|
+
| 参数 | 必填 | 说明 |
|
|
989
|
+
| --- | --- | --- |
|
|
990
|
+
| `personaId / taskId` | 是 | Agent 与接码任务 ID |
|
|
991
|
+
| `revision / idempotencyKey` | 是 | 当前任务版本与结束命令唯一键 |
|
|
992
|
+
|
|
993
|
+
返回 `data`:Phone 操作对象;通过操作和任务状态核对最终结果。
|
|
994
|
+
|
|
995
|
+
```ts
|
|
996
|
+
const { data: activationToFinish } = await qoni.genauth.agentPhone.activations.get({
|
|
997
|
+
personaId, taskId: activationTaskId,
|
|
998
|
+
})
|
|
999
|
+
const { data: activationFinish } = await qoni.genauth.agentPhone.activations.finish({
|
|
1000
|
+
personaId,
|
|
1001
|
+
taskId: activationToFinish.id,
|
|
1002
|
+
revision: activationToFinish.revision,
|
|
1003
|
+
idempotencyKey: 'activation-finish-business-001',
|
|
1004
|
+
})
|
|
1005
|
+
```
|
|
1006
|
+
|
|
1007
|
+
## Mail 管理配置
|
|
1008
|
+
|
|
1009
|
+
### 创建邮箱供应商
|
|
1010
|
+
|
|
1011
|
+
方法:`admin.providers.create`
|
|
1012
|
+
|
|
1013
|
+
配置邮箱供应商账号、命名空间、域名与收发能力。
|
|
1014
|
+
|
|
1015
|
+
| 参数 | 必填 | 说明 |
|
|
1016
|
+
| --- | --- | --- |
|
|
1017
|
+
| `name / providerType` | 是 | 配置名称;providerType 为 agentmail |
|
|
1018
|
+
| `providerAccountKey / namespaceKey` | 是 | 供应商账号与命名空间标识 |
|
|
1019
|
+
| `apiKey` | 是 | 供应商密钥,仅在服务端传入 |
|
|
1020
|
+
| `settings` | 是 | allowedDomains、defaultDomain、capabilities 等 |
|
|
1021
|
+
| `webhookSecret` | 否 | Webhook 验签密钥 |
|
|
1022
|
+
|
|
1023
|
+
返回 `data`:供应商配置对象,包含 `configId`、`revision`、服务开关与密钥配置状态。
|
|
1024
|
+
|
|
1025
|
+
```ts
|
|
1026
|
+
const { data: configuredMailProvider } = await qoni.genauth.agentMail.admin.providers.create({
|
|
1027
|
+
name: 'Business mail',
|
|
1028
|
+
providerType: 'agentmail',
|
|
1029
|
+
providerAccountKey: 'business-mail-account',
|
|
1030
|
+
namespaceKey: 'business-agent-mail',
|
|
1031
|
+
apiKey: process.env.AGENTMAIL_API_KEY!,
|
|
1032
|
+
settings: {
|
|
1033
|
+
allowedDomains: ['mail.example.com'],
|
|
1034
|
+
defaultDomain: 'mail.example.com',
|
|
1035
|
+
capabilities: ['mailbox.create', 'mail.receive', 'mail.send'],
|
|
1036
|
+
},
|
|
1037
|
+
})
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
域名与供应商账号使用实际已配置值。供应商标识与资源归属受不可变规则约束。
|
|
1041
|
+
|
|
1042
|
+
### 测试邮箱供应商
|
|
1043
|
+
|
|
1044
|
+
方法:`admin.providers.test`
|
|
1045
|
+
|
|
1046
|
+
验证供应商连通性及命名空间配置。
|
|
1047
|
+
|
|
1048
|
+
| 参数 | 必填 | 说明 |
|
|
1049
|
+
| --- | --- | --- |
|
|
1050
|
+
| `configId` | 是 | 供应商配置 ID |
|
|
1051
|
+
|
|
1052
|
+
返回 `data`:`{ connected, namespaceVerified, createsMailbox: false }`。
|
|
1053
|
+
|
|
1054
|
+
```ts
|
|
1055
|
+
const { data: mailProviderTest } = await qoni.genauth.agentMail.admin.providers.test({
|
|
1056
|
+
configId: configuredMailProvider.configId,
|
|
1057
|
+
})
|
|
1058
|
+
console.log(mailProviderTest.connected, mailProviderTest.namespaceVerified)
|
|
1059
|
+
```
|
|
1060
|
+
|
|
1061
|
+
测试不创建业务邮箱。
|
|
1062
|
+
|
|
1063
|
+
### 更新供应商
|
|
1064
|
+
|
|
1065
|
+
方法:`admin.providers.update`
|
|
1066
|
+
|
|
1067
|
+
修改配置名称、能力与服务开关。
|
|
1068
|
+
|
|
1069
|
+
| 参数 | 必填 | 说明 |
|
|
1070
|
+
| --- | --- | --- |
|
|
1071
|
+
| `configId / revision` | 是 | 配置 ID 与当前版本 |
|
|
1072
|
+
| `name / settings` | 否 | 名称与供应商设置 |
|
|
1073
|
+
| `acceptNewMailboxes / serviceEnabled` | 否 | 是否允许新建邮箱、是否启用服务 |
|
|
1074
|
+
|
|
1075
|
+
返回 `data`:更新后的供应商配置,包含新的 `revision`。
|
|
1076
|
+
|
|
1077
|
+
```ts
|
|
1078
|
+
const { data: updatedMailProvider } = await qoni.genauth.agentMail.admin.providers.update({
|
|
1079
|
+
configId: configuredMailProvider.configId,
|
|
1080
|
+
revision: configuredMailProvider.revision,
|
|
1081
|
+
acceptNewMailboxes: true,
|
|
1082
|
+
serviceEnabled: true,
|
|
1083
|
+
})
|
|
1084
|
+
```
|
|
1085
|
+
|
|
1086
|
+
### 轮换供应商密钥
|
|
1087
|
+
|
|
1088
|
+
方法:`admin.providers.rotateCredentials`
|
|
1089
|
+
|
|
1090
|
+
替换供应商 API 密钥或 Webhook 验签密钥。
|
|
1091
|
+
|
|
1092
|
+
| 参数 | 必填 | 说明 |
|
|
1093
|
+
| --- | --- | --- |
|
|
1094
|
+
| `configId / revision` | 是 | 配置 ID 与当前版本 |
|
|
1095
|
+
| `apiKey / webhookSecret` | 否 | 需要轮换的密钥,至少提供一个 |
|
|
1096
|
+
|
|
1097
|
+
返回 `data`:更新后的配置对象,不返回明文密钥。
|
|
1098
|
+
|
|
1099
|
+
```ts
|
|
1100
|
+
const { data: rotatedMailProvider } = await qoni.genauth.agentMail.admin.providers.rotateCredentials({
|
|
1101
|
+
configId: updatedMailProvider.configId,
|
|
1102
|
+
revision: updatedMailProvider.revision,
|
|
1103
|
+
apiKey: process.env.AGENTMAIL_NEW_API_KEY!,
|
|
1104
|
+
})
|
|
1105
|
+
```
|
|
1106
|
+
|
|
1107
|
+
### 创建提取模板
|
|
1108
|
+
|
|
1109
|
+
方法:`admin.templates.create`
|
|
1110
|
+
|
|
1111
|
+
保存可复用的邮件匹配和验证码提取规则。
|
|
1112
|
+
|
|
1113
|
+
| 参数 | 必填 | 说明 |
|
|
1114
|
+
| --- | --- | --- |
|
|
1115
|
+
| `name / platformKey` | 是 | 模板名称与平台标识 |
|
|
1116
|
+
| `match / extract` | 是 | 匹配条件与提取规则 |
|
|
1117
|
+
| `enabled` | 否 | 是否启用模板 |
|
|
1118
|
+
|
|
1119
|
+
返回 `data`:模板对象,包含 `id`、`matchRule`、`extractRule`、`enabled`、`version`。
|
|
1120
|
+
|
|
1121
|
+
```ts
|
|
1122
|
+
const { data: mailTemplate } = await qoni.genauth.agentMail.admin.templates.create({
|
|
1123
|
+
name: 'Demo platform code',
|
|
1124
|
+
platformKey: 'demo-platform',
|
|
1125
|
+
match: { fromDomains: ['demo.example.com'] },
|
|
1126
|
+
extract: { kind: 'code', pattern: 'Code[: ]*([0-9]{6})' },
|
|
1127
|
+
enabled: true,
|
|
1128
|
+
})
|
|
1129
|
+
```
|
|
1130
|
+
|
|
1131
|
+
创建验证码任务时传 `templateId: mailTemplate.id`,省略 `match` / `extract`。
|
|
1132
|
+
|
|
1133
|
+
### 测试与更新提取模板
|
|
1134
|
+
|
|
1135
|
+
方法:`admin.templates.test` / `update`
|
|
1136
|
+
|
|
1137
|
+
用样例邮件验证规则,再更新已保存模板。
|
|
1138
|
+
|
|
1139
|
+
| 参数 | 必填 | 说明 |
|
|
1140
|
+
| --- | --- | --- |
|
|
1141
|
+
| `match / extract / sender / subject / text` | 否 | test 必填:规则与样例邮件 |
|
|
1142
|
+
| `templateId / version` | 否 | update 必填:模板 ID 与当前业务版本 |
|
|
1143
|
+
| `name / platformKey / match / extract` | 否 | update 必填:更新后的模板配置 |
|
|
1144
|
+
|
|
1145
|
+
返回 `data`:test 返回 `{ status, values }`,状态为 `matched`、`ambiguous` 或 `unmatched`;update 返回模板对象。
|
|
1146
|
+
|
|
1147
|
+
```ts
|
|
1148
|
+
const { data: templateTest } = await qoni.genauth.agentMail.admin.templates.test({
|
|
1149
|
+
match: mailTemplate.matchRule,
|
|
1150
|
+
extract: mailTemplate.extractRule,
|
|
1151
|
+
sender: 'no-reply@demo.example.com',
|
|
1152
|
+
subject: 'Verification code',
|
|
1153
|
+
text: 'Code: 123456',
|
|
1154
|
+
})
|
|
1155
|
+
const { data: updatedTemplate } = await qoni.genauth.agentMail.admin.templates.update({
|
|
1156
|
+
templateId: mailTemplate.id,
|
|
1157
|
+
version: mailTemplate.version,
|
|
1158
|
+
name: mailTemplate.name,
|
|
1159
|
+
platformKey: mailTemplate.platformKey,
|
|
1160
|
+
match: mailTemplate.matchRule,
|
|
1161
|
+
extract: mailTemplate.extractRule,
|
|
1162
|
+
enabled: true,
|
|
1163
|
+
})
|
|
1164
|
+
```
|
|
1165
|
+
|
|
1166
|
+
模板使用业务字段 `version`,不是资源的 `revision`。
|
|
1167
|
+
|
|
1168
|
+
### 对账未知操作
|
|
1169
|
+
|
|
1170
|
+
方法:`admin.operations.reconcile`
|
|
1171
|
+
|
|
1172
|
+
请求服务端核对供应商结果未知的创建或发送操作。
|
|
1173
|
+
|
|
1174
|
+
| 参数 | 必填 | 说明 |
|
|
1175
|
+
| --- | --- | --- |
|
|
1176
|
+
| `operationId` | 是 | 原操作 ID |
|
|
1177
|
+
|
|
1178
|
+
返回 `data`:`{ operationId, status, reconcileScheduled: true }`。之后查询原操作。
|
|
1179
|
+
|
|
1180
|
+
```ts
|
|
1181
|
+
const { data: mailReconciliation } = await qoni.genauth.agentMail.admin.operations.reconcile({
|
|
1182
|
+
operationId: 'unknown-mail-operation-id',
|
|
1183
|
+
})
|
|
1184
|
+
```
|
|
1185
|
+
|
|
1186
|
+
发送结果需要人工确认时,`admin.operations.resolveSend` 接收 `outcome`、`evidenceRef` 与可选 `providerMessageId`,只根据已核实的供应商证据确认。
|
|
1187
|
+
|
|
1188
|
+
## Phone 管理配置
|
|
1189
|
+
|
|
1190
|
+
### 创建号码供应商
|
|
1191
|
+
|
|
1192
|
+
方法:`admin.providers.create`
|
|
1193
|
+
|
|
1194
|
+
配置 Twilio 长期号码或 5sim 一次性接码供应商。
|
|
1195
|
+
|
|
1196
|
+
| 参数 | 必填 | 说明 |
|
|
1197
|
+
| --- | --- | --- |
|
|
1198
|
+
| `name / provider / credentials` | 是 | 名称、twilio 或 5sim、对应供应商凭据 |
|
|
1199
|
+
| `settings` | 是 | 国家、服务、币种、预算、已验证的计价与操作路由 |
|
|
1200
|
+
|
|
1201
|
+
返回 `data`:配置对象,包含 `id`、`enabled`、`revision`、`credentialsConfigured`、`health`。
|
|
1202
|
+
|
|
1203
|
+
```ts
|
|
1204
|
+
const { data: configuredPhoneProvider } = await qoni.genauth.agentPhone.admin.providers.create({
|
|
1205
|
+
name: 'Business Twilio',
|
|
1206
|
+
provider: 'twilio',
|
|
1207
|
+
credentials: {
|
|
1208
|
+
accountSid: process.env.TWILIO_ACCOUNT_SID!,
|
|
1209
|
+
authToken: process.env.TWILIO_AUTH_TOKEN!,
|
|
1210
|
+
},
|
|
1211
|
+
settings: {
|
|
1212
|
+
countries: ['US'],
|
|
1213
|
+
services: [],
|
|
1214
|
+
currency: 'USD',
|
|
1215
|
+
dailyLimit: '10.000000',
|
|
1216
|
+
pricingVerified: false,
|
|
1217
|
+
verifiedRoutes: [],
|
|
1218
|
+
},
|
|
1219
|
+
})
|
|
1220
|
+
```
|
|
1221
|
+
|
|
1222
|
+
Twilio 凭据使用 `accountSid` / `authToken`;5sim 使用 `{ token }`。按供应商实际计价填写预算和费用上限,完成价格核验后再设置 `pricingVerified` 与 `verifiedRoutes`。
|
|
1223
|
+
|
|
1224
|
+
### 测试供应商
|
|
1225
|
+
|
|
1226
|
+
方法:`admin.providers.test` / `admin.operations.wait`
|
|
1227
|
+
|
|
1228
|
+
创建供应商健康检查任务,使用管理员凭据等待结果。
|
|
1229
|
+
|
|
1230
|
+
| 参数 | 必填 | 说明 |
|
|
1231
|
+
| --- | --- | --- |
|
|
1232
|
+
| `configId / revision` | 是 | 配置 ID 与当前版本 |
|
|
1233
|
+
| `idempotencyKey` | 是 | 健康检查命令的唯一键 |
|
|
1234
|
+
|
|
1235
|
+
返回 `data`:Phone 操作对象。等待后重新查询配置中的 `health`。
|
|
1236
|
+
|
|
1237
|
+
```ts
|
|
1238
|
+
const { data: providerHealthOperation } = await qoni.genauth.agentPhone.admin.providers.test({
|
|
1239
|
+
configId: configuredPhoneProvider.id,
|
|
1240
|
+
revision: configuredPhoneProvider.revision,
|
|
1241
|
+
idempotencyKey: 'phone-provider-test-001',
|
|
1242
|
+
})
|
|
1243
|
+
const { data: providerHealthResult } = await qoni.genauth.agentPhone.admin.operations.wait({
|
|
1244
|
+
operationId: providerHealthOperation.id,
|
|
1245
|
+
}, { timeoutMs: 120_000 })
|
|
1246
|
+
const { data: testedPhoneProviders } = await qoni.genauth.agentPhone.admin.providers.list()
|
|
1247
|
+
const testedPhoneProvider = testedPhoneProviders.items.find(item => item.id === configuredPhoneProvider.id)
|
|
1248
|
+
if (!testedPhoneProvider) throw new Error('Provider configuration not found')
|
|
1249
|
+
console.log(providerHealthResult.status, testedPhoneProvider.health)
|
|
1250
|
+
```
|
|
1251
|
+
|
|
1252
|
+
健康检查与 Mail 测试不同,返回异步操作。健康结果有有效期;配置修改后旧结果失效,需重新测试。
|
|
1253
|
+
|
|
1254
|
+
### 更新号码供应商
|
|
1255
|
+
|
|
1256
|
+
方法:`admin.providers.update`
|
|
1257
|
+
|
|
1258
|
+
修改配置、轮换凭据或启停供应商。
|
|
1259
|
+
|
|
1260
|
+
| 参数 | 必填 | 说明 |
|
|
1261
|
+
| --- | --- | --- |
|
|
1262
|
+
| `configId / revision` | 是 | 配置 ID 与当前版本 |
|
|
1263
|
+
| `name / settings / credentials / enabled` | 否 | 需要修改的配置字段 |
|
|
1264
|
+
|
|
1265
|
+
返回 `data`:更新后的供应商对象与 `revision`。
|
|
1266
|
+
|
|
1267
|
+
```ts
|
|
1268
|
+
const { data: updatedPhoneProvider } = await qoni.genauth.agentPhone.admin.providers.update({
|
|
1269
|
+
configId: testedPhoneProvider.id,
|
|
1270
|
+
revision: testedPhoneProvider.revision,
|
|
1271
|
+
name: 'Business Twilio primary',
|
|
1272
|
+
})
|
|
1273
|
+
```
|
|
1274
|
+
|
|
1275
|
+
配置变更后重新执行健康检查,再按业务需求启用。仅启用配置不会自动开放采购和发送。
|
|
1276
|
+
|
|
1277
|
+
### 配置访问策略
|
|
1278
|
+
|
|
1279
|
+
方法:`admin.policies.create` / `list` / `update`
|
|
1280
|
+
|
|
1281
|
+
限制管理账号或访问密钥可操作的 Agent、资源、动作与费用。
|
|
1282
|
+
|
|
1283
|
+
| 参数 | 必填 | 说明 |
|
|
1284
|
+
| --- | --- | --- |
|
|
1285
|
+
| `actorId / actorType` | 是 | 主体 ID;admin 或 key |
|
|
1286
|
+
| `personaIds / resourceIds / actions / enabled` | 是 | Agent 范围、资源范围、动作与启用状态 |
|
|
1287
|
+
| `limits / expiresAt` | 否 | 费用限制与毫秒时间戳截止时间 |
|
|
1288
|
+
| `policyId / revision` | 否 | update 必填;策略 ID 与当前版本 |
|
|
1289
|
+
|
|
1290
|
+
返回 `data`:create / update 返回策略对象与 `revision`;list 返回 `{ items }`。
|
|
1291
|
+
|
|
1292
|
+
```ts
|
|
1293
|
+
const { data: phonePolicy } = await qoni.genauth.agentPhone.admin.policies.create({
|
|
1294
|
+
actorId: process.env.GENAUTH_ACCESS_KEY_ID!,
|
|
1295
|
+
actorType: 'key',
|
|
1296
|
+
personaIds: [personaId],
|
|
1297
|
+
resourceIds: [resourceId],
|
|
1298
|
+
actions: ['phone.read', 'sms.read', 'sms.content.read', 'verification.read', 'verification.create', 'verification.consume'],
|
|
1299
|
+
enabled: true,
|
|
1300
|
+
})
|
|
1301
|
+
const { data: phonePolicies } = await qoni.genauth.agentPhone.admin.policies.list()
|
|
1302
|
+
const { data: updatedPhonePolicy } = await qoni.genauth.agentPhone.admin.policies.update({
|
|
1303
|
+
policyId: phonePolicy.id,
|
|
1304
|
+
revision: phonePolicy.revision,
|
|
1305
|
+
actorId: phonePolicy.actorId,
|
|
1306
|
+
actorType: phonePolicy.actorType,
|
|
1307
|
+
personaIds: phonePolicy.personaIds,
|
|
1308
|
+
resourceIds: phonePolicy.resourceIds,
|
|
1309
|
+
actions: phonePolicy.actions,
|
|
1310
|
+
enabled: false,
|
|
1311
|
+
})
|
|
1312
|
+
```
|
|
1313
|
+
|
|
1314
|
+
按实际资源与动作授权。读取验证码值需要 `sms.content.read`;采购、释放、发送、消费各有独立权限。create 与停用示例按业务需要分别调用。
|
|
1315
|
+
|
|
1316
|
+
### 登记与归档人工号码
|
|
1317
|
+
|
|
1318
|
+
方法:`admin.numbers.register` / `archive`
|
|
1319
|
+
|
|
1320
|
+
记录已有的人工号码,或归档不再使用的号码记录。
|
|
1321
|
+
|
|
1322
|
+
| 参数 | 必填 | 说明 |
|
|
1323
|
+
| --- | --- | --- |
|
|
1324
|
+
| `personaId / phone` | 否 | register 必填;Agent ID 与号码 |
|
|
1325
|
+
| `label` | 否 | 号码备注名称 |
|
|
1326
|
+
| `resourceId / revision / reason` | 否 | archive 必填;资源 ID、当前版本与原因 |
|
|
1327
|
+
|
|
1328
|
+
返回 `data`:register 返回号码对象;archive 返回 `{ id, revision }`。
|
|
1329
|
+
|
|
1330
|
+
```ts
|
|
1331
|
+
const { data: manualNumber } = await qoni.genauth.agentPhone.admin.numbers.register({
|
|
1332
|
+
personaId,
|
|
1333
|
+
phone: '+12025550124',
|
|
1334
|
+
label: 'Existing business contact',
|
|
1335
|
+
})
|
|
1336
|
+
const { data: archivedNumber } = await qoni.genauth.agentPhone.admin.numbers.archive({
|
|
1337
|
+
resourceId: manualNumber.id,
|
|
1338
|
+
revision: manualNumber.revision,
|
|
1339
|
+
reason: 'No longer used',
|
|
1340
|
+
})
|
|
1341
|
+
```
|
|
1342
|
+
|
|
1343
|
+
登记不代表供应商已开通短信能力;归档是记录操作,供应商号码释放使用 `numbers.release`。存在当前账号绑定时先处理绑定。
|
|
1344
|
+
|
|
1345
|
+
### 查询号码绑定
|
|
1346
|
+
|
|
1347
|
+
方法:`admin.numbers.bindings`
|
|
1348
|
+
|
|
1349
|
+
释放或归档前查询号码与外部账号的关联。
|
|
1350
|
+
|
|
1351
|
+
| 参数 | 必填 | 说明 |
|
|
1352
|
+
| --- | --- | --- |
|
|
1353
|
+
| `resourceId` | 是 | 号码资源 ID |
|
|
1354
|
+
|
|
1355
|
+
返回 `data`:`{ items }`,每项包含 `accountId`、`platformKey`、`username`、`purposes`、`isCurrent`。
|
|
1356
|
+
|
|
1357
|
+
```ts
|
|
1358
|
+
const { data: phoneBindings } = await qoni.genauth.agentPhone.admin.numbers.bindings({ resourceId })
|
|
1359
|
+
console.log(phoneBindings.items)
|
|
1360
|
+
```
|
|
1361
|
+
|
|
1362
|
+
### 核对未知操作
|
|
1363
|
+
|
|
1364
|
+
方法:`admin.operations.reconcile`
|
|
1365
|
+
|
|
1366
|
+
对供应商结果未知的号码、短信或接码操作提交核对。
|
|
1367
|
+
|
|
1368
|
+
| 参数 | 必填 | 说明 |
|
|
1369
|
+
| --- | --- | --- |
|
|
1370
|
+
| `operationId` | 是 | 原操作 ID |
|
|
1371
|
+
| `providerObjectId / evidenceRef` | 否 | 经核实的供应商对象 ID 与证据引用 |
|
|
1372
|
+
|
|
1373
|
+
返回 `data`:Phone 操作对象。随后查询同一个操作,不创建替代采购或发送。
|
|
1374
|
+
|
|
1375
|
+
```ts
|
|
1376
|
+
const { data: phoneReconciliation } = await qoni.genauth.agentPhone.admin.operations.reconcile({
|
|
1377
|
+
operationId: 'unknown-phone-operation-id',
|
|
1378
|
+
evidenceRef: 'provider-support-ticket-id',
|
|
1379
|
+
})
|
|
1380
|
+
```
|
|
1381
|
+
|
|
1382
|
+
## 幂等、版本、分页与等待
|
|
1383
|
+
|
|
1384
|
+
| 参数 / 返回字段 | 行为 |
|
|
1385
|
+
| --- | --- |
|
|
1386
|
+
| `idempotencyKey` | 放入 `Idempotency-Key` 请求头,不进入业务 JSON。对同一业务命令保存并复用同一键;参数改变应作为新命令处理 |
|
|
1387
|
+
| `revision` | 正整数,映射为 `If-Match: "N"`;`412` 后重新读取并由业务决定是否再修改 |
|
|
1388
|
+
| `meta.etag` | 保留服务端带引号的 ETag;`meta.httpStatus` 保留通信接口 HTTP 状态 |
|
|
1389
|
+
| Mail 列表 | `{ items, nextCursor }`,下一页用 `cursor`;`limit` 1–100 |
|
|
1390
|
+
| Phone 号码列表 | `{ items, total, page, limit }`;其他列表通常是至多 100 条的 `{ items }` |
|
|
1391
|
+
| `operations.wait` / `verifications.wait` | 默认总超时 120 秒、最短轮询间隔 1 秒;尊重 Mail 的 `pollAfterSeconds`。通过第二参数配置 `timeoutMs`、`pollIntervalMs`、`signal` |
|
|
1392
|
+
|
|
1393
|
+
等待方法只做 GET。到达未知、失败或需业务处理的状态时直接返回原响应;总超时抛出 `QoniTimeoutError`,不会取消服务端操作。继续查询原 `operationId`;Phone 操作对象的 ID 字段名是 `id`,Mail 是 `operationId`。
|
|
1394
|
+
|
|
1395
|
+
## 错误处理
|
|
1396
|
+
|
|
1397
|
+
`QoniResponse<T>` 保留 `{ data, meta }`。通信错误的 `error.code` 和 `error.retryable` 透传到 `QoniError`,并保留 HTTP 状态、请求 ID 与原始响应。
|
|
1398
|
+
|
|
1399
|
+
| 错误 / 状态 | 处理方式 |
|
|
1400
|
+
| --- | --- |
|
|
1401
|
+
| `401` / `403` | 检查标准 AK/SK、用户池、管理员身份与 Phone 策略。显式 bearer 由调用方更新 |
|
|
1402
|
+
| `PRECONDITION_FAILED` / `412` | 读取当前对象并核对修改意图;不要直接重放旧版本 |
|
|
1403
|
+
| `RESULT_UNKNOWN`、操作 `unknown` | 查询原操作,必要时通过管理侧对账;不要换键采购或发送 |
|
|
1404
|
+
| `RESULT_AMBIGUOUS` | 读取候选并显式选择 `candidateId` |
|
|
1405
|
+
| `CONTENT_EXPIRED` / `RESULT_UNAVAILABLE` | 正文或结果已经不可读取;发起新的业务流程 |
|
|
1406
|
+
| 路由 `404` | 检查 `genauthHost` 与请求地址 |
|
|
1407
|
+
|
|
1408
|
+
## 方法参考
|
|
1409
|
+
|
|
1410
|
+
用户、组织和权限管理见 [GenAuth 管理 SDK](./genauth-management)。
|