Lingara Lingara 說明文件 學習指南 API 函式庫 應用程式 起造 網頁版
語言: 閩南語

Webhook 佮事件

API 版本 2026-10-affable-towhee

Lingara 會共你帳號的課程計畫佮用量發生的代誌記做事件,嘛會收你的遊戲抑是應用程式送來的事件。逐个事件,無論按怎傳送,攏用仝款的封包,事件目錄共全部的事件攏列出來。

封包

逐个事件攏紮六个欄位。id 用 lgr_evt_ 開頭,是獨一的,是用來去除重複的鍵。type 講是啥物事件。created_at 是事件發生的時間。api_version 是 data 所用的版本:就是你的用戶端固定的版本;佇事件源佮事件串流,就是你的請求佇 Lingara-Version 指定的版本。subject 用 lgr_sub_ 開頭,講這个事件是關係啥人:對你的用戶端來講伊袂變,毋過逐个用戶端攏無仝,而且永遠毋是電子批地址、名抑是帳號 ID。data 真細,干焦講出資源,袂共資源複製:請用需要的權限範圍去提資源。

有兩種類型愛各講一句。lesson_plan.ready 對仝一份計畫可能會到兩擺,頭一擺 data.status 是 partial,紲落來是 complete:你會當照頭一擺的提一份會當用的計畫,抑是等 complete 才提齊逐組內容。usage.threshold_reached 干焦會為照用量計費的帳號佮用戶端傳送,一擺超過幾若个門檻的時,干焦會報超過的上懸彼个,所以毋通預期逐个門檻攏有一个事件。

一份紀錄,三種聽法

Webhook 適合有公開 HTTPS 端點的伺服器。事件源佮事件串流適合無公開端點的程式,比如佇玩家電腦運作的遊戲。逐種方式的封包攏仝款,所以程式會當先用事件源,後擺才換用 Webhook,讀事件的方法免改。事件路由是予原生程式用的。佇瀏覽器內底運作的遊戲這馬猶呼叫袂著,因為 /v1/ 袂回應跨來源預檢請求。

啥人會收著事件

用戶端愛有 events:read 佮彼个事件類型本身的權限範圍(事件目錄有列),而且事件是關係這个用戶端的擁有者,伊才會收著這个事件。佇事件源佮事件串流,存取權杖的權限範圍會閣縮狹範圍,types 會共伊縮狹到你指名的類型。webhook.test 干焦會送去伊指定的端點,永遠袂入去事件源,嘛袂當訂閱。app.installed 佮 app.uninstalled 干焦會送予應用程式家己的用戶端,永遠袂送予仝一个帳號的別个用戶端。

註冊端點

佇 Lingara 網頁應用程式的 Webhook 頁面(網址是 app.getlingara.com/admin/webhooks)註冊端點,愛先揀用戶端。端點 URL 一定愛佇連接埠 443 用 https,伊的主機干焦會當解析到公開的地址。揀欲傳送的事件:干焦會列出用戶端的權限範圍允准的類型。URL 佮欲傳送的事件後擺攏袂當改:請加一个新端點,閣共舊的刪除。簽名密鑰用 lgr_whsec_ 開頭,干焦顯示一擺。

驗證傳送

逐擺傳送攏是一个 POST,照 Standard Webhooks 規格,紮三个標頭:webhook-id(事件的 id)、webhook-timestamp 佮 webhook-signature。HMAC 金鑰是簽名密鑰內底 lgr_whsec_ 後壁彼部分用 base64 解碼的結果,永遠毋是規个密鑰字串。請佇解析內容進前,用伊原本的位元組驗證,像下跤按呢。時間戳記佮這馬差超過五分鐘的傳送愛拒絕,這是 Standard Webhooks 函式庫的預設值:按呢會當防止予人攔著的傳送閣予人重送。

signed   = webhook-id + "." + webhook-timestamp + "." + raw request body
key      = base64_decode(the secret after its prefix)
expected = "v1," + base64(hmac_sha256(key, signed))
accept   if |now - webhook-timestamp| <= 5 minutes
         and some entry of webhook-signature (space-separated) equals expected
             (compare in constant time)

Standard Webhooks 為大部分的語言發佈驗證函式庫。這寡函式庫預期密鑰寫做 whsec_ 加 base64,抑是干焦 base64,所以愛共 Lingara 密鑰內底 lgr_whsec_ 後壁彼部分交予伊。Lingara 家己的函式庫接受規个密鑰。

緊回應,預備會重試

請佇 10 秒內用任何 2xx 回應,了後才做工課。其他任何結果,包括逾時抑是 3xx(袂綴重新導向),攏會用愈來愈長的間隔重試差不多一工。對自動傳送回應 410,端點隨就停用;對測試抑是重新傳送回應 410 就袂。連紲五工傳送失敗了後,端點嘛會停用。無論佗一種,攏會寄電子批予伊的擁有者。Lingara 這爿的故障永遠袂算入停用端點。佇 Webhook 頁面,你會當傳送測試,抑是重新傳送最近 30 工內的任何一擺傳送。逐擺攏干焦試一擺,永遠袂重試,就算端點已經停用嘛會照送。

傳送上少一擺,而且無保證順序。仝一个事件可能會到兩擺,重試嘛可能佇較晏的事件後壁才到。webhook-id 逐擺重試攏仝款,佇 30 工內的重新傳送嘛仝款。請共你處理過的逐个 id 記 30 工,重複的就莫插。若順序要緊,就照 created_at 排。

輪換簽名密鑰

一个端點會當仝時有兩个簽名密鑰。兩个攏有效的時陣,webhook-signature 會紮兩个 v1, 項目,接受其中一个的接收端就會當照常運作。請共新密鑰加入你的伺服器閣部署,然後才撤銷舊的。

事件源

用用戶端的存取權杖呼叫 GET /v1/events,會回傳 items(封包)、next_cursor 佮 has_more。權杖需要 events:read 佮你欲收的逐種類型的權限範圍:若干焦有 events:read,事件源是空的。伊對這馬開始。傳 start=oldest 就會提著差不多最近 30 工的事件。伊免公開端點,嘛免簽名密鑰:存取權杖就證明是啥人咧問。下跤的換取要求課程計畫事件需要的兩个權限範圍。

export LINGARA_TOKEN="$(curl -sS --fail-with-body -X POST "https://api.getlingara.com/oauth/token" \
  -u "$LINGARA_CLIENT_ID:$LINGARA_CLIENT_SECRET" \
  -d "grant_type=client_credentials" \
  --data-urlencode "scope=events:read lesson_plans:read" | jq -r '.access_token // error(.error)')"
curl "https://api.getlingara.com/v1/events" \
  -H "Authorization: Bearer $LINGARA_TOKEN"

next_cursor 一定會有:請共伊存起來,閣當做 cursor 送轉來。伊是不透明的。has_more 是 true 就是愛隨閣呼叫,是 false 就是你已經綴上矣:較停仔才閣輪詢,抑是開事件串流。超過 30 工的游標會予人拒絕,回傳 410 佮 cursor_expired。若無游標,事件源對這馬開始,中間的事件會跳過。欲共遐的事件提轉來,就用 start=oldest 呼叫,伊會追到事件保留上早的時間,閣跳過你已經處理過的 id 值。

事件串流

GET /v1/events/stream 用伺服器傳送事件的形式送仝款的事件。逐个 event 框的 data 是一个封包,逐个框的 id: 是一个游標,佮 next_cursor 是仝一款值,所以你會當佇事件源佮事件串流之間切換,袂漏去。連線斷去、收著 done 框(事件串流有時會家己結束)抑是 error 框了後,請共 Last-Event-ID 設做你收著的上尾一个 id:,閣重新連線。大部分的 SSE 用戶端會替你做這步,Lingara 函式庫的 tailEvents 嘛是(內底的 streamEvents 干焦是單一連線)。伊是游標,毋是事件的 id。事件串流會送心跳,所以恬恬無聲的連線就是斷去的連線。

curl -N "https://api.getlingara.com/v1/events/stream" \
  -H "Authorization: Bearer $LINGARA_TOKEN"

共事件送予 Lingara

用 events:write 呼叫 POST /v1/events,用 {type, data} 的形式共事件送予 Lingara:world.context_changed(一个 scene、source_lang、target_lang、level,閣會當加一个紮 name 佮 persona 的 npc,閣有 tags)抑是 world.practice_requested(一个 topic,佮仝款的語言佮程度)。Idempotency-Key 是必要的:上濟 255 个看會著的 ASCII 字元,比如 UUID。若無伊,回應是 400 佮 idempotency_key_required。逐个事件設一擺,重試的時陣送仝一个鍵。一个鍵就是一个事件:一工內,用仝一个鍵的第二个請求會提著頭一擺的回應(用 JSON 來看相等,毋是逐位元組仝款),就算內容無仝嘛仝款;了後伊會提著仝一个事件,像下跤按呢。送入來的事件無簽名:你的存取權杖就是證明。請描寫世界,毋是玩家:scene、npc、topic 抑是 tags 內底毋通有名抑是開講的內容。

export LINGARA_TOKEN="$(curl -sS --fail-with-body -X POST "https://api.getlingara.com/oauth/token" \
  -u "$LINGARA_CLIENT_ID:$LINGARA_CLIENT_SECRET" \
  -d "grant_type=client_credentials" \
  --data-urlencode "scope=events:write lesson_plans:write" | jq -r '.access_token // error(.error)')"
curl -X POST "https://api.getlingara.com/v1/events" \
  -H "Authorization: Bearer $LINGARA_TOKEN" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -H "Content-Type: application/json" \
  -d '{"type":"world.context_changed","data":{"scene":"A night market in Taipei, just after rain","npc":{"name":"Auntie Lin","persona":"a street-food vendor who likes to haggle"},"source_lang":"en","target_lang":"zh","level":3,"tags":["market","food","chapter-2"],"generate":true}}'

逐个文字欄位攏是一逝看會著的字元,去掉頭尾的空白才算:scene 佮 topic 上濟 160,npc.name 上濟 32,npc.persona 上濟 120。換逝、定位字元佮其他控制字元會予人拒絕,看袂著的字元佮格式字元嘛仝款:方向覆寫字元、零寬度字元(某寡文字佮表情符號需要的連接字元無算)、標籤區塊佮私人使用區字元。tags 上濟有 8 个細寫的機器記號,逐个上濟 24 个字元,永遠袂入去課程計畫。level 是 1 到 9,兩種語言一定愛無仝。超過這寡限制的請求會予人拒絕,回傳 400,嘛袂記任何事件。

用 "generate": true(world.practice_requested 的預設值)的時陣,權杖閣需要 lesson_plans:write。若無伊,請求會予人拒絕,回傳 403,袂記任何事件。若有伊,Lingara 會開始一份課程計畫,檢查佮收費攏佮直接建立一份仝款,202 回應內底的 reaction 會講發生啥物代誌。若是 started 閣 plan_status 是 generating,紲落來佇你用的逐種方式攏會收著一个 lesson_plan.ready 抑是 lesson_plan.failed,伊的 data.plan_id 就是回應內底的 plan_id。若是 partial 抑是 complete,計畫是對計畫庫來的,這馬就會當讀,嘛無保證會有事件:猶是可能會到一个,所以干焦 generating 才值得等。若是 refused 抑是 failed,事件猶原成立。伊袂用仝一个鍵重試,所以欲閣試就送一个新事件。

一工內的重試會提著頭一擺的回應。了後的重試會對存起來的事件重新組出來,伊保留事件開始的計畫,毋過無保留反應予人拒絕的原因。所以較晏的重試可能會用 reaction failed 佮 internal 回應:意思是頭一擺的結果無記著,毋是講無計畫。你若有留 plan_id,就用伊讀計畫,抑是送一个新事件。

Tidewater Games:無伺服器的遊戲

Tidewater Games 是一間虛構的工作室,用 Godot 咧做一款予玩家去夜市四界行的遊戲。伊的開發者佇家己的電腦、用家己的用戶端運作這款遊戲。

玩家行入去一个麵擔。遊戲用 "generate": true 送出 world.context_changed(就是頂懸「共事件送予 Lingara」彼節的指令),閣共回應內底的 plan_id 留起來。

若 plan_status 是 generating,遊戲就讀事件串流,抑是輪詢事件源,一直到紮彼个 plan_id 的 lesson_plan.ready 到。然後伊用 lesson_plans:read 讀計畫,像下跤按呢。若計畫已經是 complete,伊就隨讀。

export LINGARA_TOKEN="$(curl -sS --fail-with-body -X POST "https://api.getlingara.com/oauth/token" \
  -u "$LINGARA_CLIENT_ID:$LINGARA_CLIENT_SECRET" \
  -d "grant_type=client_credentials" \
  --data-urlencode "scope=lesson_plans:read" | jq -r '.access_token // error(.error)')"
curl "https://api.getlingara.com/v1/lesson-plans/$ID" \
  -H "Authorization: Bearer $LINGARA_TOKEN"

後來工作室加一台有 HTTPS 端點的細台伺服器,閣為 lesson_plan.ready 共伊註冊。仝一个事件會紮仝一个 id 送到遐,遊戲讀事件的程式碼免改。

用戶端密鑰永遠毋通佮遊戲版本做伙發佈,因為玩家裝置頂懸啥物攏讀會著。佇 Lingara 支援代替玩家登入進前,佇玩家電腦運作的遊戲愛佮家己的伺服器溝通,干焦開發者家己彼份才直接佮 Lingara 溝通。

事件按怎算錢

佮逐擺 /v1/ 呼叫仝款,你用戶端的用量會算逐个接受的送入事件、逐擺事件源呼叫佮逐擺開的事件串流。用 "generate": true 送的事件嘛會算做一份課程計畫。逐擺 Webhook 傳送照逐个事件逐个端點算一擺,佇伊頭一擺 2xx 的時算,無論彼是第幾擺試。了後永遠袂閣算,測試嘛永遠袂算。GET /v1/usage 會顯示這個月到今的用量。

若是翻譯佮英文參考文件無仝,就以英文參考文件為準。