VYSLO DEVELOPER PLATFORM
Back to vyslo.ai

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 needNotes
A VYSLO accountThe same account you use in the app. User and developer are roles, not separate logins.
The API base URLhttps://api.vyslo.ai:8443/api/v1/app — a public certificate, usable from curl, a browser or a server.
A card, eventuallySteps 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 用的同一套短信登入。

bash
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 是授權回跳必須命中的白名單。

bash
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"]
      }'
201 · response
{
  "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
}
STORE THESE NOW

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

bash
# 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 步的方式:

bash
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>
WHY THE CALLBACK IS CHECKED HERE

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 頭。

bash
curl -s "$BASE/open/ext/recordings/rec_01J9…" \
  -H "X-Vyslo-Token: $CAP"
200 · response
{
  "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."
  ]
}
bash · audio original
# 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 值。先校驗再解析,並用恆定時間比較。

node · express
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 表示用戶撤銷了授權,或應用被封禁。請刪除本地令牌,重新引導用戶授權——不要重試。

bash
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

kotlin
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

swift
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