QUICKSTART
From zero to a transcript
Six steps on the cloud path: log in, register an app, point a webhook at your server, get a user's approval, read the recording, keep the token fresh. A new app starts in sandbox, where only your own account can authorize it — so you can walk the whole flow before anyone else sees it.
雲通路六步:登入、建立應用、把 webhook 指向你的伺服器、取得用戶同意、讀出錄音、保持令牌新鮮。 新應用處於 sandbox 狀態,只有你自己的帳號能授權——整條流程可以在沒有任何外部用戶的情況下走通。
Before you start
| You need | Notes |
|---|---|
| A VYSLO account | The same account you use in the app. User and developer are roles, not separate logins. |
| The API base URL | https://api.vyslo.ai:8443/api/v1/app — a public certificate, usable from curl, a browser or a server. |
| A card, eventually | Steps 1–4 and 6 need no hardware. To see a real recording.ready you need a card syncing through the app, or an existing recording on your account. |
| 你需要 | 說明 |
|---|---|
| 一個 VYSLO 帳號 | 就是你在 App 裡用的那個。用戶與開發者是角色,不是兩套登入。 |
| API 根地址 | https://api.vyslo.ai:8443/api/v1/app——公共證書,curl、瀏覽器、伺服器都能用。 |
| 一張卡(最後才需要) | 第 1–4、6 步不需要硬件。要看到真實的 recording.ready,需要有卡經 App 同步,或帳號下已有錄音。 |
1 · Get an account token
Everything you do as the developer or as the user is authenticated with your account
token in an Authorization: Bearer header. It comes from the same SMS login the app uses.
凡是以開發者或以用戶身份做的事,都用帳號令牌鑑權,放在 Authorization: Bearer
頭裡。它來自 App 用的同一套短信登入。
BASE=https://api.vyslo.ai:8443/api/v1/app
# 1. Ask for the SMS code
curl -s -X POST "$BASE/auth/sms/send" \
-H 'Content-Type: application/json' \
-d '{"phone":"13800138000"}'
# 2. Exchange phone + code for an access token
curl -s -X POST "$BASE/auth/login" \
-H 'Content-Type: application/json' \
-d '{"phone":"13800138000","code":"123456"}'
# {"accessToken":"eyJ…","userId":"7f3c…","phone":"13800138000", …}
TOKEN=eyJ…
2 · Register your app
requestedScopes is a bitmap — see Scopes & tokens. Ask
only for what you will use: the token a user signs is the intersection of this registration and
what they approve. callbackUris is the allowlist your authorization callback must hit.
requestedScopes 是位圖,見權限與令牌。只申請你會用到的:
用戶簽出的令牌是「這次登記」與「用戶同意」的交集。callbackUris 是授權回跳必須命中的白名單。
curl -s -X POST "$BASE/open/apps" \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"name": "Meeting Notes Bot",
"requestedScopes": 17,
"callbackUris": ["notesbot://vyslo-auth"]
}'
{
"appId": 42,
"name": "Meeting Notes Bot",
"status": "sandbox",
"requestedScopes": 17,
"callbackUris": ["notesbot://vyslo-auth"],
"createdAt": "2026-10-30T06:12:44Z",
"appSecret": "G7m…", // returned once, never again
"webhookSecret": "qT4…" // sign/verify webhook bodies with this
}
appSecret is shown in this response only — the server keeps a hash. 17
above is recordings.read (1) + recordings.audio (16); drop the 16 if you
do not need the audio file. New apps are sandbox: only your own account can authorize
them, and webhooks only fire for your own recordings.
appSecret 只在這次回應裡出現——服務端只保存哈希。上面的 17 是
recordings.read(1)+ recordings.audio(16);不需要音頻原件就去掉 16。
新應用是 sandbox 態:只有你自己的帳號能授權,webhook 也只為你自己的錄音觸發。
3 · Point the webhook at your server
# 204 No Content on success. Send {"url":""} to clear it.
curl -s -X POST "$BASE/open/apps/42/webhook" \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"url":"https://notesbot.example.com/hooks/vyslo"}'
# The callback allowlist is replaced wholesale, up to 10 entries:
curl -s -X POST "$BASE/open/apps/42/callbacks" \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"callbackUris":["notesbot://vyslo-auth","https://notesbot.example.com/auth/return"]}'
4 · Get a user's approval
In production you send the user into the VYSLO app, which shows the consent screen and calls back to your allowlisted URI with the capability token. On Android and iOS the SDK builds that request for you; the deep link contract is on the SDK page.
While your app is in sandbox you can also mint your own token directly, because you are both the developer and the user. That is the fastest way to get to step 5:
正式環境下,你把用戶引到 VYSLO App,由它顯示同意頁,再帶能力令牌回跳到你登記過的地址。 在 Android 與 iOS 上,SDK 會替你構造這個請求;深鏈契約見 SDK 頁。
應用還在 sandbox 時,你同時是開發者和用戶,可以直接為自己簽出令牌——這是最快走到第 5 步的方式:
curl -s -X POST "$BASE/open/authorize" \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"appId":42,"scopes":17,"callback":"notesbot://vyslo-auth"}'
# {"token":"<capability token>","issuedAt":"2026-10-30T06:20:01Z"}
CAP=<capability token>
callback must hit the allowlist you registered in step 3 — exactly, or with
?/# and your own parameters appended. The check happens
before a token is issued, so a token can never be redirected to an address its
app did not register. A callback that is not on the list is refused.
callback 必須命中你在第 3 步登記的白名單——完全相等,或在登記項後追加
?/# 及你自己的參數。校驗發生在簽發令牌之前,
所以令牌永遠不會被導向應用沒有登記過的地址。不在白名單裡的 callback 直接被拒。
5 · Read the recording
From here on you are no longer acting as an account — you are acting as the app, carrying the
capability token in X-Vyslo-Token. Drop the Authorization header.
從這一步起,你不再以帳號身份調用,而是以應用身份,用 X-Vyslo-Token 攜帶能力令牌。
請去掉 Authorization 頭。
curl -s "$BASE/open/ext/recordings/rec_01J9…" \
-H "X-Vyslo-Token: $CAP"
{
"recordingId": "rec_01J9…",
"title": "Thursday standup",
"status": "ready",
"recordedOn": "2026-10-29",
"timeLabel": "09:14",
"createdAt": "2026-10-29T09:41:08Z",
"ownerVerified": true,
"svVerdict": "owner",
"segments": [
{"speaker": "S1", "text": "Let's start with the firmware side.", "timestamp": "00:02"},
{"speaker": "S2", "text": "Board 5 is back from power tuning.", "timestamp": "00:07"}
],
"summaryLines": [
"Firmware: board 5 power tuning finished, waiting on a re-measure.",
"Owner committed to sending the updated budget on Friday."
]
}
# Needs recordings.audio (bit 16) in the grant; streams the stored file.
curl -s "$BASE/open/ext/recordings/rec_01J9…/audio" \
-H "X-Vyslo-Token: $CAP" -o recording.opus
6 · Verify the webhook signature
Every delivery carries X-Vyslo-Signature: the hex HMAC-SHA256 of the raw body
under your webhookSecret. Verify before you parse, and compare in constant time.
每次投遞都帶 X-Vyslo-Signature:用你的 webhookSecret 對原始
請求體做 HMAC-SHA256 的 hex 值。先校驗再解析,並用恆定時間比較。
import crypto from 'node:crypto';
import express from 'express';
const app = express();
const SECRET = process.env.VYSLO_WEBHOOK_SECRET;
// Raw body — a re-serialized JSON object will not hash to the same value.
app.post('/hooks/vyslo', express.raw({ type: 'application/json' }), (req, res) => {
const expected = crypto.createHmac('sha256', SECRET).update(req.body).digest('hex');
const got = Buffer.from(req.get('X-Vyslo-Signature') || '', 'utf8');
const want = Buffer.from(expected, 'utf8');
if (got.length !== want.length || !crypto.timingSafeEqual(got, want)) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body.toString('utf8'));
res.sendStatus(204); // ack fast, then work
queue.add(event.recordingId); // idempotent: retries repeat recordingId
});
7 · Keep the token fresh
A capability token expires 60 days after it was issued — the offline grace period, so a card and
an app that lose connectivity keep working. Renew it with the token itself, roughly weekly;
renewIfNeeded() in the Android and iOS SDKs already rate-limits to 7 days.
A 403 means the user revoked you or the app was banned. Delete your copy of the
token and send the user through authorization again — do not retry.
能力令牌在簽發後 60 天過期——這是離線寬限期,讓斷網的卡與 App 仍能工作。用令牌本身續簽,大約每週一次;
Android 與 iOS SDK 的 renewIfNeeded() 已內建 7 天限頻。
收到 403 表示用戶撤銷了授權,或應用被封禁。請刪除本地令牌,重新引導用戶授權——不要重試。
curl -s -X POST "$BASE/open/ext/token/renew" \
-H "X-Vyslo-Token: $CAP"
# {"token":"<fresh token>","issuedAt":"2026-10-30T06:31:12Z"}
The same flow with the Android SDK
val vyslo = VysloOpen(context, appId = 42L)
// Authorize: the VYSLO app shows the consent screen, then deep-links back.
startActivity(vyslo.authorizeIntent(
scopes = VysloOpen.SCOPE_RECORDINGS_READ,
callbackUri = "notesbot://vyslo-auth",
))
// In the activity that handles notesbot://vyslo-auth
vyslo.handleAuthorizationCallback(intent.data) // true = token stored
// On a worker thread, after your server saw recording.ready
val rec = vyslo.fetchRecording(recordingId)
rec.ownerVerified // cloud voiceprint review says this is the card's owner
rec.segments // speaker / text / timestamp
rec.summaryLines
The same flow with the iOS SDK
let vyslo = VysloOpen(appId: 42)
// Authorize: the VYSLO app shows the consent screen, then opens your callback URL.
UIApplication.shared.open(vyslo.authorizeURL(
scopes: [.recordingsRead],
callbackURI: "notesbot://vyslo-auth"
))
// In .onOpenURL (SwiftUI) or scene(_:openURLContexts:) (UIKit)
vyslo.handleAuthorizationCallback(url) // true = token stored
// After your server saw recording.ready
let rec = try await vyslo.fetchRecording(recordingID)
rec.identity // who is speaking, with the source of the verdict
rec.segments // speaker / text / timestamp / identity
rec.summaryLines
Android SDK
Every method, the deep link contract and the token store.
iOS SDK
The same surface in Swift, with the Info.plist keys iOS needs.
REST API
All thirteen endpoints, request and response shapes, error codes.
Webhooks
Trigger conditions, retry schedule and the privacy gate.