Mga webhook at event
Bersyon ng API 2026-10-affable-towhee
Itinatala ng Lingara bilang mga event ang nangyayari sa mga lesson plan at paggamit ng iyong account, at tumatanggap ito ng mga event mula sa iyong laro o app. Iisa ang envelope ng bawat event, saanmang daan ito dumaan, at nakalista silang lahat sa katalogo ng mga event.
Ang envelope
Anim na field ang dala ng bawat event. Nagsisimula ang id sa lgr_evt_, natatangi ito, at ito ang susi para sa pag-alis ng mga duplicate. Pinapangalanan ng type ang event. Ang created_at ay kung kailan ito nangyari. Ang api_version ay ang bersyong sinusunod ng hugis ng data: ang bersyong nakakabit sa iyong client, o, sa feed at sa stream, ang bersyong pinangalanan ng iyong request sa Lingara-Version. Nagsisimula ang subject sa lgr_sub_ at sinasabi nito kung tungkol kanino ang event: hindi ito nagbabago para sa iyong client pero iba ito para sa bawat client, at hindi ito kailanman email, pangalan o ID ng account. Maliit ang data at pinapangalanan nito ang mga resource sa halip na kopyahin ang mga ito: kunin ang isang resource gamit ang scope na kailangan nito.
Dalawang type ang nangangailangan ng tig-isang pangungusap. Maaaring dumating nang dalawang beses ang lesson_plan.ready para sa isang plan, una nang may data.status na partial at pagkatapos ay complete: kumilos sa una para sa magagamit nang plan, o hintayin ang complete para makuha ang bawat set. Ipinapadala lamang ang usage.threshold_reached para sa mga metered na account at client, at kapag nalampasan nang sabay ang ilang threshold, ang pinakamataas lamang na nalampasan ang iniuulat, kaya huwag umasa ng isang event bawat threshold.
Iisang log, tatlong paraan para marinig ito
Bagay ang mga webhook sa server na may pampublikong HTTPS endpoint. Bagay ang feed at ang stream sa programang wala nito, gaya ng laro sa makina ng isang player. Iisa ang envelope sa bawat daan, kaya maaaring magsimula ang isang programa sa feed at lumipat sa mga webhook sa kalaunan nang hindi binabago kung paano nito binabasa ang isang event. Sumasagot ang mga ruta ng event sa mga native na programa. Hindi pa sila matatawag ng larong tumatakbo sa browser, dahil hindi sumasagot ang /v1/ sa anumang cross-origin preflight.
Sino ang nakakarinig ng event
Naririnig ng isang client ang isang event kapag hawak nito ang events:read at ang sariling scope ng type ng event, na nakalista sa katalogo, at kapag tungkol sa may-ari ng client ang event. Sa feed at sa stream, lalo pa itong pinakikitid ng mga scope ng access token, at pinakikitid ito ng types sa mga type na pinangalanan mo. Napupunta lamang ang webhook.test sa endpoint na pinagpadalhan nito, hindi kailanman sa feed, at hindi ito maaaring i-subscribe. Napupunta lamang ang app.installed at app.uninstalled sa sariling client ng app, hindi kailanman sa ibang client ng parehong account.
Magrehistro ng endpoint
Magrehistro ng endpoint sa pahinang Mga webhook ng Lingara web app, sa app.getlingara.com/admin/webhooks, at piliin muna ang client. Dapat gumamit ang URL nito ng https sa port 443, at dapat mag-resolve lamang ang host nito sa mga pampublikong address. Piliin ang “Mga kaganapang ipapadala”: ang mga type lamang na pinapayagan ng mga scope ng client ang iniaalok. Hindi na mababago ang URL at ang mga event sa kalaunan: magdagdag ng bagong endpoint at burahin ang luma. Nagsisimula ang secret sa pagpirma sa lgr_whsec_ at isang beses lamang itong ipinapakita.
Beripikahin ang isang paghahatid
Bawat paghahatid ay isang POST na may tatlong header, ayon sa Standard Webhooks specification: webhook-id (ang id ng event), webhook-timestamp at webhook-signature. Ang HMAC key ay ang bahagi ng secret pagkatapos ng lgr_whsec_, na na-decode mula sa base64, hindi kailanman ang secret bilang string. Beripikahin bago i-parse ang body, sa mga raw byte nito, gaya ng nasa ibaba. Tanggihan ang paghahatid na ang timestamp ay mahigit limang minuto ang layo mula ngayon, ang default ng mga library ng Standard Webhooks: pinipigilan nito ang muling pag-replay ng nahuling paghahatid.
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)Naglalathala ang Standard Webhooks ng mga verifier para sa karamihan ng mga wika. Inaasahan nila ang secret na nakasulat bilang whsec_ na sinusundan ng base64, o bilang base64 lamang, kaya ibigay sa kanila ang bahagi ng Lingara secret pagkatapos ng lgr_whsec_. Tinatanggap ng sariling mga library ng Lingara ang buong secret.
Sumagot agad, asahan ang muling pagsubok
Sumagot ng anumang 2xx sa loob ng 10 segundo, at gawin ang trabaho pagkatapos. Anumang iba pa, kasama ang timeout o 3xx (hindi sinusundan ang mga redirect), ay sinusubukang muli nang may lumalaking pagitan nang mga isang araw. Ang 410 bilang sagot sa awtomatikong paghahatid ay agad na nagdi-disable sa endpoint; ang 410 bilang sagot sa pagsubok o muling paghahatid ay hindi. Pagkatapos ng limang araw ng mga pumalyang paghahatid, nadi-disable rin ang endpoint. Alinman dito, pinapadalhan ng email ang may-ari nito. Hindi kailanman ibinibilang sa pag-disable ng endpoint ang problema sa panig ng Lingara. Mula sa pahinang Mga webhook, maaari kang “Magpadala ng pagsubok”, o “Ihatid muli” ang anumang paghahatid sa huling 30 araw. Isang pagtatangka lamang ang bawat isa, hindi kailanman inuulit, at ipinapadala ito kahit sa naka-disable na endpoint.
Hindi bababa sa isang beses ang paghahatid at walang tiyak na pagkakasunod-sunod. Maaaring dumating nang dalawang beses ang parehong event, at maaaring dumating ang muling pagsubok pagkatapos ng mas bagong event. Pareho ang webhook-id sa bawat muling pagsubok, at sa muling paghahatid hanggang 30 araw pagkatapos. Itala ang bawat id na naproseso mo nang 30 araw, at huwag pansinin ang pag-uulit. Ayusin ayon sa created_at kung mahalaga ang pagkakasunod-sunod.
Palitan ang secret sa pagpirma
Maaaring humawak ang isang endpoint ng dalawang secret sa pagpirma nang sabay. Habang parehong aktibo, dalawang v1, na entry ang dala ng webhook-signature, at patuloy na gumagana ang receiver na tumatanggap sa alinman. Idagdag ang bagong secret sa iyong server, i-deploy ito, saka bawiin ang luma.
Ang feed
Ang GET /v1/events gamit ang access token ng isang client ay nagbabalik ng items (mga envelope), next_cursor at has_more. Kailangan ng token ang events:read at ang scope ng bawat type na gusto mong marinig: kung events:read lamang, walang laman ang feed. Nagsisimula ito mula ngayon. Ipasa ang start=oldest para sa mga event ng humigit-kumulang huling 30 araw. Hindi ito nangangailangan ng pampublikong endpoint o secret sa pagpirma: pinapatunayan ng access token kung sino ang nagtatanong. Hinihingi ng pagpapalit sa ibaba ang parehong scope na kailangan ng mga event ng lesson plan.
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"Laging naroon ang next_cursor: itago ito at ipasa pabalik bilang cursor. Opaque ito. Ang has_more na true ay nangangahulugang tumawag muli ngayon, at ang false ay nangangahulugang nakahabol ka na: mag-poll mamaya, o buksan ang stream. Ang cursor na mas luma sa 30 araw ay tinatanggihan nang may 410 at cursor_expired. Kung walang cursor, nagsisimula ang feed mula ngayon, at nalalaktawan ang mga event sa pagitan. Para mabawi ang mga ito, tumawag nang may start=oldest, na umaabot pabalik hangga't itinatago ang mga event, at laktawan ang mga id value na naproseso mo na.
Ang stream
Dala ng GET /v1/events/stream ang parehong mga event bilang server-sent events. Ang data ng bawat event frame ay isang envelope, at ang id: ng bawat frame ay isang cursor, ang parehong token ng next_cursor, kaya maaari kang lumipat sa pagitan ng feed at stream nang walang puwang. Pagkatapos ng naputol na koneksyon, isang done frame (paminsan-minsang tinatapos ng stream ang sarili nito) o isang error frame, kumonekta muli nang nakatakda ang Last-Event-ID sa huling id: na natanggap mo. Ginagawa ito para sa iyo ng karamihan ng mga SSE client, at gayundin ng tailEvents sa mga library ng Lingara (iisang koneksyon lamang ang streamEvents doon). Cursor ito, hindi ang id ng event. Nagpapadala ang stream ng heartbeat, kaya patay ang tahimik na koneksyon.
curl -N "https://api.getlingara.com/v1/events/stream" \
-H "Authorization: Bearer $LINGARA_TOKEN"Magpadala ng event sa Lingara
Ang POST /v1/events na may events:write ay nagpapadala ng event sa Lingara bilang {type, data}: world.context_changed (isang scene, source_lang, target_lang, level, at kung nais, isang npc na may name at persona, at tags) o world.practice_requested (isang topic at ang parehong mga wika at antas). Kailangan ang Idempotency-Key: hanggang 255 nakikitang ASCII character, gaya ng UUID. Kung wala ito, ang sagot ay 400 at idempotency_key_required. Itakda ito nang isang beses bawat event, at ipadala ang parehong key sa muling pagsubok. Isang key ay isang event: sa loob ng isang araw, ang ikalawang request na may parehong key ay nakakakuha ng unang sagot (pareho bilang JSON, hindi byte por byte), kahit iba ang body nito, at pagkatapos niyon ay nakakakuha ito ng parehong event, gaya ng nasa ibaba. Hindi pinipirmahan ang mga papasok na event: ang iyong access token ang patunay. Ilarawan ang mundo, hindi kailanman ang player: walang pangalan o chat sa scene, npc, topic o 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}}'Bawat text field ay isang linya ng nakikitang character, binibilang pagkatapos i-trim: scene at topic hanggang 160, npc.name hanggang 32, at npc.persona hanggang 120. Tinatanggihan ang mga line break, tab at iba pang control character, at gayundin ang mga hindi nakikita at formatting character: mga direction override, mga zero-width character maliban sa mga joiner na kailangan ng ilang script at emoji, ang tag block at mga private-use character. Naglalaman ang tags ng hanggang 8 lowercase na machine token na tig-hanggang 24 character, at hindi kailanman umaabot sa lesson plan. Ang level ay 1 hanggang 9, at dapat magkaiba ang dalawang wika. Ang request na lampas sa mga limitasyong ito ay tinatanggihan nang may 400 at walang naitatalang event.
Kapag may "generate": true (ang default para sa world.practice_requested), kailangan din ng token ang lesson_plans:write. Kung wala ito, tinatanggihan ang request nang may 403 at walang naitatalang event. Kung mayroon, nagsisimula ang Lingara ng lesson plan, na may parehong mga pagsusuri at parehong singil gaya ng direktang paggawa nito, at sinasabi ng reaction ng sagot na 202 kung ano ang nangyari. Kapag started at ang plan_status ay generating, susunod ang isang lesson_plan.ready o lesson_plan.failed na ang data.plan_id ay ang plan_id ng sagot, sa bawat daang ginagamit mo. Kapag partial o complete, galing ang plan sa library at mababasa na ngayon, at walang ipinapangakong event: maaari pa ring may dumating, kaya generating lamang ang sulit hintayin. Kapag refused o failed, nananatili pa rin ang event. Hindi ito inuulit sa ilalim ng parehong key, kaya magpadala ng bagong event para subukang muli.
Ang muling pagsubok sa loob ng isang araw ay nakakakuha ng unang sagot. Ang muling pagsubok pagkatapos niyon ay binubuo muli mula sa nakaimbak na event, na nag-iingat sa plan na sinimulan nito pero hindi sa dahilan kung bakit tinanggihan ang isang reaksyon. Kaya maaaring sumagot ang huling muling pagsubok nang may reaction na failed at internal: nangangahulugan iyon na hindi naitala ang unang kinalabasan, hindi na walang plan. Basahin ang plan gamit ang plan_id nito kung itinago mo ito, o magpadala ng bagong event.
Tidewater Games: larong walang server
Ang Tidewater Games, isang kathang-isip na studio, ay gumagawa ng larong Godot kung saan ginagalugad ng player ang isang night market. Pinapatakbo ng developer nito ang laro sa sarili nitong makina, gamit ang sarili nitong client.
Pumasok ang player sa isang noodle stall. Nagpo-post ang laro ng world.context_changed na may "generate": true, ang command sa seksyon ng mga papasok na event sa itaas, at itinatago ang plan_id mula sa sagot.
Kung generating ang plan_status, binabasa ng laro ang stream, o pinopoll ang feed, hanggang dumating ang isang lesson_plan.ready na may plan_id na iyon. Saka nito binabasa ang plan gamit ang lesson_plans:read, gaya ng nasa ibaba. Kung complete na ang plan, binabasa nito ito agad.
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"Sa kalaunan, nagdaragdag ang studio ng maliit na server na may HTTPS endpoint at inirerehistro ito para sa lesson_plan.ready. Doon dumarating ang parehong event, na may parehong id, at hindi nagbabago ang code ng laro para basahin ito.
Hindi kailanman dapat isama ang secret ng client sa build ng laro, dahil mababasa ang anumang nasa device ng player. Hangga't hindi pa sinusuportahan ng Lingara ang pag-sign in para sa isang player, ang larong nasa mga makina ng mga player ay nakikipag-usap sa sarili nitong server, at ang sariling kopya lamang ng developer ang direktang nakikipag-usap sa Lingara.
Magkano ang mga event
Binibilang ng paggamit ng iyong client ang bawat tinanggap na papasok na event, bawat tawag sa feed at bawat stream na binuksan, gaya ng pagbilang nito sa bawat tawag sa /v1/. Ang event na ipinadala nang may "generate": true ay binibilang din bilang lesson plan. Binibilang nang isang beses ang bawat paghahatid ng webhook bawat event bawat endpoint, sa unang 2xx nito, alinmang pagtatangka iyon. Hindi na ito kailanman binibilang muli, at hindi kailanman binibilang ang pagsubok. Ipinapakita ng GET /v1/usage ang buwan hanggang ngayon.
Kung magkaiba ang isang salin at ang sangguniang Ingles, ang sangguniang Ingles ang tama.