Webhake en gebeurtenisse
API-weergawe 2026-10-affable-towhee
Lingara teken aan wat met jou rekening se lesplanne en gebruik gebeur as gebeurtenisse, en aanvaar gebeurtenisse van jou speletjie of toep. Elke gebeurtenis, watter pad dit ook al volg, het dieselfde koevert, en die gebeurteniskatalogus lys hulle almal.
Die koevert
Elke gebeurtenis dra ses velde. id begin met lgr_evt_, is uniek, en is die sleutel waarop duplikate verwyder word. type benoem die gebeurtenis. created_at is wanneer dit gebeur het. api_version is die weergawe waarvolgens data gevorm is: jou kliënt se vasgepende weergawe, of, op die voer en die stroom, die weergawe wat jou versoek in Lingara-Version genoem het. subject begin met lgr_sub_ en sê oor wie die gebeurtenis gaan: dit is stabiel vir jou kliënt maar verskil vir elke kliënt, en dit is nooit 'n e-posadres, 'n naam of 'n rekening-ID nie. data is klein en benoem hulpbronne eerder as om hulle te kopieer: haal 'n hulpbron met die omvang wat dit benodig.
Twee tipes verdien elk 'n sin. lesson_plan.ready kan twee keer vir een plan aankom, eers met data.status partial en dan complete: tree op die eerste op vir 'n bruikbare plan, of wag vir complete om elke stel te hê. usage.threshold_reached word slegs vir gemeterde rekeninge en kliënte gestuur, en 'n sprong verby verskeie drempels rapporteer slegs die hoogste een wat oorgesteek is, so moenie een gebeurtenis per drempel verwag nie.
Een logboek, drie maniere om dit te hoor
Webhake pas 'n bediener met 'n openbare HTTPS-eindpunt. Die voer en die stroom pas 'n program wat nie een het nie, soos 'n speletjie op 'n speler se masjien. Die koevert is dieselfde langs elke pad, so 'n program kan op die voer begin en later na webhake skuif sonder om te verander hoe dit 'n gebeurtenis lees. Die gebeurtenisroetes antwoord inheemse programme. 'n Speletjie wat in 'n blaaier loop, kan hulle nog nie oproep nie, want /v1/ antwoord geen cross-origin-preflight nie.
Wie hoor 'n gebeurtenis
'n Kliënt hoor 'n gebeurtenis wanneer dit events:read en die gebeurtenistipe se eie omvang hou, wat die katalogus lys, en wanneer die gebeurtenis oor die kliënt se eienaar gaan. Op die voer en die stroom vernou die toegangtoken se omvange dit verder, en types vernou dit tot die tipes wat jy noem. webhook.test gaan slegs na die eindpunt waarheen dit gestuur is, nooit na die voer nie, en jy kan nie daarop inteken nie. app.installed en app.uninstalled gaan slegs na die toep se eie kliënt, nooit na 'n ander kliënt van dieselfde rekening nie.
Registreer 'n eindpunt
Registreer 'n eindpunt op die Webhake-bladsy van die Lingara-webtoep, by app.getlingara.com/admin/webhooks, en kies eers die kliënt. Die URL moet https op poort 443 gebruik, en die gasheer moet slegs na openbare adresse oplos. Kies die “Gebeurtenisse om te stuur”: slegs die tipes wat die kliënt se omvange toelaat, word aangebied. Die URL en die gebeurtenisse kan nie later gewysig word nie: voeg 'n nuwe eindpunt by en skrap die ou een. Die ondertekengeheim begin met lgr_whsec_ en word slegs een keer gewys.
Verifieer 'n aflewering
Elke aflewering is 'n POST met drie kopskrifte, volgens die Standard Webhooks-spesifikasie: webhook-id (die gebeurtenis se id), webhook-timestamp en webhook-signature. Die HMAC-sleutel is die base64-gedekodeerde deel van die geheim ná lgr_whsec_, nooit die geheim as 'n string nie. Verifieer voordat jy die liggaam ontleed, oor sy rou grepe, soos hieronder. Weier 'n aflewering waarvan die tydstempel meer as vyf minute van nou af is, die Standard Webhooks-biblioteke se verstek: dit keer dat 'n onderskepte aflewering herspeel word.
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 publiseer verifieerders vir die meeste tale. Hulle verwag 'n geheim geskryf as whsec_ gevolg deur base64, of as kaal base64, so gee hulle die deel van die Lingara-geheim ná lgr_whsec_. Lingara se eie biblioteke aanvaar die hele geheim.
Antwoord vinnig, verwag herhalings
Antwoord met enige 2xx binne 10 sekondes, en doen die werk daarna. Enigiets anders, insluitend 'n uitteltyd of 'n 3xx (herleidings word nie gevolg nie), word vir sowat 'n dag met groeiende tussenposes weer probeer. 'n 410 in antwoord op 'n outomatiese aflewering deaktiveer die eindpunt onmiddellik; 'n 410 in antwoord op 'n toets of 'n heraflewering doen dit nie. Ná vyf dae van mislukte aflewerings word die eindpunt ook gedeaktiveer. Hoe ook al, die eienaar kry 'n e-pos. 'n Fout aan Lingara se kant tel nooit vir die deaktivering van 'n eindpunt nie. Op die Webhake-bladsy kan jy “Stuur toets” druk, of “Lewer weer af” op enige aflewering van die laaste 30 dae. Elkeen is een poging, word nooit herhaal nie, en word selfs na 'n gedeaktiveerde eindpunt gestuur.
Aflewering is minstens een keer en sonder volgorde. Dieselfde gebeurtenis kan twee keer aankom, en 'n herhaling kan ná 'n latere gebeurtenis aankom. webhook-id is dieselfde by elke herhaling, en by 'n heraflewering tot 30 dae later. Teken elke id wat jy hanteer het vir 30 dae aan, en ignoreer 'n herhaling. Sorteer volgens created_at as volgorde saak maak.
Roteer 'n ondertekengeheim
'n Eindpunt kan twee ondertekengeheime tegelyk hê. Terwyl albei aktief is, dra webhook-signature twee v1,-inskrywings, en 'n ontvanger wat enigeen aanvaar, bly werk. Voeg die nuwe geheim by jou bediener, ontplooi dit, en herroep dan die ou een.
Die voer
GET /v1/events met 'n kliënt se toegangtoken gee items (koeverte), next_cursor en has_more terug. Die token benodig events:read en die omvang van elke tipe wat jy wil hoor: met slegs events:read is die voer leeg. Dit begin van nou af. Gee start=oldest vir die gebeurtenisse van ongeveer die laaste 30 dae. Dit benodig geen openbare eindpunt en geen ondertekengeheim nie: die toegangtoken bewys wie vra. Die inruiling hieronder vra vir albei omvange wat die lesplangebeurtenisse benodig.
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 is altyd teenwoordig: stoor dit en gee dit terug as cursor. Dit is ondeursigtig. has_more true beteken roep nou weer, en false beteken jy is op datum: peil later, of maak die stroom oop. 'n Wyser ouer as 30 dae word met 410 en cursor_expired geweier. Sonder 'n wyser begin die voer van nou af, en die gebeurtenisse tussenin word oorgeslaan. Om hulle te herwin, roep met start=oldest, wat so ver terugreik as wat gebeurtenisse gehou word, en slaan die id-waardes oor wat jy reeds hanteer het.
Die stroom
GET /v1/events/stream dra dieselfde gebeurtenisse as server-sent events. Elke event-raam se data is een koevert, en elke raam se id: is 'n wyser, dieselfde token as next_cursor, so jy kan sonder 'n gaping tussen die voer en die stroom wissel. Ná 'n verbroke verbinding, 'n done-raam (die stroom beëindig homself van tyd tot tyd) of 'n error-raam, koppel weer met Last-Event-ID gestel op die laaste id: wat jy ontvang het. Die meeste SSE-kliënte doen dit vir jou, en so ook tailEvents in Lingara se biblioteke (streamEvents daar is 'n enkele verbinding). Dit is 'n wyser, nie die gebeurtenis se id nie. Die stroom stuur 'n hartklop, so 'n stil verbinding is 'n dooie een.
curl -N "https://api.getlingara.com/v1/events/stream" \
-H "Authorization: Bearer $LINGARA_TOKEN"Stuur 'n gebeurtenis na Lingara
POST /v1/events met events:write stuur 'n gebeurtenis na Lingara as {type, data}: world.context_changed ('n scene, source_lang, target_lang, level, en opsioneel 'n npc met 'n name en persona, en tags) of world.practice_requested ('n topic en dieselfde tale en vlak). Idempotency-Key is verpligtend: tot 255 sigbare ASCII-karakters, soos 'n UUID. Daarsonder is die antwoord 400 en idempotency_key_required. Stel dit een keer per gebeurtenis, en stuur dieselfde sleutel by 'n herhaling. Een sleutel is een gebeurtenis: binne 'n dag kry 'n tweede versoek met dieselfde sleutel die eerste antwoord (gelyk as JSON, nie greep vir greep nie), selfs as sy liggaam verskil, en daarna kry dit dieselfde gebeurtenis, soos hieronder. Inkomende gebeurtenisse word nie onderteken nie: jou toegangtoken is die bewys. Beskryf die wêreld, nooit die speler nie: geen name of klets in scene, npc, topic of tags nie.
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}}'Elke teksveld is een reël sigbare karakters, getel ná afknipping: scene en topic tot 160, npc.name tot 32, en npc.persona tot 120. Reëlbreuke, oortjies en ander beheerkarakters word geweier, en so ook onsigbare en formateringskarakters: rigtingoorheersings, nulwydte-karakters behalwe die verbinders wat sommige skrifte en emoji nodig het, die tag-blok en privaatgebruik-karakters. tags hou tot 8 kleinletter-masjientekens van elk tot 24 karakters, en bereik nooit die lesplan nie. level is 1 tot 9, en die twee tale moet verskil. 'n Versoek buite hierdie limiete word met 400 geweier en teken geen gebeurtenis aan nie.
Met "generate": true (die verstek vir world.practice_requested) benodig die token ook lesson_plans:write. Daarsonder word die versoek met 403 geweier en geen gebeurtenis aangeteken nie. Daarmee begin Lingara 'n lesplan, met dieselfde kontroles en dieselfde rekening as wanneer jy een direk skep, en die 202-antwoord se reaction sê wat gebeur het. Met started en plan_status generating volg 'n lesson_plan.ready of lesson_plan.failed waarvan die data.plan_id die antwoord se plan_id is, langs elke pad wat jy gebruik. Met partial of complete kom die plan uit die biblioteek en kan dit nou gelees word, en geen gebeurtenis word belowe nie: een kan steeds aankom, so slegs generating is die moeite werd om voor te wag. Met refused of failed staan die gebeurtenis steeds. Dit word nie onder dieselfde sleutel herhaal nie, so stuur 'n nuwe gebeurtenis om weer te probeer.
'n Herhaling binne 'n dag kry die eerste antwoord terug. 'n Herhaling daarna word herbou uit die gestoorde gebeurtenis, wat die plan hou wat dit begin het maar nie waarom 'n reaksie geweier is nie. Dus kan 'n laat herhaling met reaction failed en internal antwoord: dit beteken die eerste uitkoms is nie aangeteken nie, nie dat geen plan bestaan nie. Lees die plan volgens sy plan_id as jy dit gehou het, of stuur 'n nuwe gebeurtenis.
Tidewater Games: 'n speletjie sonder bediener
Tidewater Games, 'n fiktiewe ateljee, bou 'n Godot-speletjie waarin die speler 'n nagmark verken. Sy ontwikkelaar laat die speletjie op hul eie masjien loop, met hul eie kliënt.
Die speler stap 'n noedelstalletjie binne. Die speletjie pos world.context_changed met "generate": true, die opdrag in die afdeling oor inkomende gebeurtenisse hierbo, en hou die plan_id uit die antwoord.
As plan_status generating is, lees die speletjie die stroom, of peil die voer, totdat 'n lesson_plan.ready met daardie plan_id aankom. Dan lees dit die plan met lesson_plans:read, soos hieronder. As die plan reeds complete was, lees dit dit onmiddellik.
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"Later voeg die ateljee 'n klein bediener met 'n HTTPS-eindpunt by en registreer dit vir lesson_plan.ready. Dieselfde gebeurtenis kom daar aan, met dieselfde id, en die speletjie se kode om dit te lees verander nie.
'n Kliëntgeheim mag nooit binne 'n speletjiebou versend word nie, want enigiets op 'n speler se toestel kan gelees word. Totdat Lingara aanmelding namens 'n speler ondersteun, praat 'n speletjie op spelers se masjiene met sy eie bediener, en slegs die ontwikkelaar se eie kopie praat direk met Lingara.
Wat gebeurtenisse kos
Jou kliënt se gebruik tel elke aanvaarde inkomende gebeurtenis, elke voeroproep en elke stroom wat oopgemaak word, soos dit elke /v1/-oproep tel. 'n Gebeurtenis wat met "generate": true gestuur word, tel ook as 'n lesplan. Elke webhaak-aflewering tel een keer per gebeurtenis per eindpunt, by sy eerste 2xx, watter poging dit ook al is. Dit tel nooit weer nie, en 'n toets tel nooit nie. GET /v1/usage wys die maand tot dusver.
Indien 'n vertaling en die Engelse verwysing verskil, is die Engelse verwysing korrek.