Transskribering i Make.com: byg flowet omkring webhooks
Et transskriberingsjob er minutter om at blive færdigt. Et Make-scenarie afregnes pr. modulkørsel. De to ting trækker hver sin vej, og det er præcis den spænding, denne guide i virkeligheden handler om.
Den oplagte løsning — send en fil ind, og vent så, tjek, vent, tjek indtil den er klar — koster ingenting på en server, du selv driver. I Make er den ikke gratis. Hver ventetid og hvert statustjek er en operation, og et job på fire minutter kan brænde tredive af dem af på ikke at lave andet end at spørge »er den snart færdig?«.
Vi bygger det derfor omvendt. Inwista siger til Make i det øjeblik, arbejdet er færdigt, og scenariet, der griber beskeden, er tre moduler langt.
Til sidst har du:
- Et modtagerscenarie, der vågner, når en transskribering er klar
- Et afsenderscenarie, der afleverer filer til Inwista og derefter stopper
- Signaturverificering, så modtageren kun stoler på ægte hændelser
- Valgfri tilføjelser — oversættelser parallelt, frasortering af dubletter og en oprydning efter opbevaringstid
Det hele kører på det offentlige Inwista API v1 gennem standardmodulet HTTP i Make. Ingen egen app, ingen kode.
Før du går i gang
Du skal bruge tre ting:
- En Make-konto — gratisplanen er fin til at bygge det her, selvom loftet over antal operationer bliver snævert i produktion
- En API-nøgle fra Inwista — opret en under Mit arbejdsområde → API-nøgler. Den begynder med
inw_live_ - Medier, API'et kan nå — API'et forventer en offentlig
https-adresse, så filer i Dropbox, Google Drive, S3 eller dit eget publiceringsværktøj har brug for et delbart eller signeret link
Du skal ikke hoste et webhook-endepunkt nogen steder. Make giver dig adressen.
En bemærkning om omkostninger, før du bygger noget, der kører uden opsyn: transskribering afregnes med 4 kreditter pr. påbegyndt medieminut og trækkes, når jobbet tages imod. Job, der fejler, refunderes automatisk. Ret scenariet mod et par korte testfiler, før du slipper det løs på dit arkiv.
Hvorfor opbygningen er afgørende her
Begge løsninger virker. De koster bare vidt forskelligt, og i Make hober den forskel sig op hver måned.
Et scenarie med polling til et job, der bliver færdigt på cirka fire minutter, og som tjekker hvert tyvende sekund, ser omtrent sådan ud: én indsendelse, så tolv runder med ventetid plus statustjek plus router, og til sidst hentning og levering. Regn med 39 operationer pr. fil.
Webhook-varianten deler sig i to scenarier. Afsenderen er en trigger og ét HTTP-kald. Modtageren er en webhook, en parsning, en hentning og en levering. Regn med 6 operationer pr. fil.
Med 200 optagelser om måneden bliver det 7.800 operationer mod 1.200 — forskellen mellem at skulle opgradere abonnementet og en afrundingsfejl. Det fjerner også de to fejlsituationer, der rammer pollende scenarier i produktion: en kørsel, der varer længe nok til at ramme loftet på 40 minutter i Make, og et job, der er gået i stå og looper hele natten, uden at nogen opdager det.
Byg modtageren først. Det er den del, der skal sidde.
Trin 1: opret modtageren
Nyt scenarie. Tilføj et modul, vælg Webhooks → Custom webhook, klik på Add, giv den et navn som inwista-transcripts, og kopiér adressen, Make giver dig.
Før du forlader dialogen, skal du åbne webhookens avancerede indstillinger og slå JSON pass-through til.
Det er indstillingen, alle overser, og den er værd at forstå frem for bare at kopiere. Inwista signerer hver levering med en HMAC, der beregnes over de rå bytes i forespørgslens body. Hvis Make parser JSON'en for dig, er præcis de bytes væk — rækkefølgen på nøglerne og mellemrummene inklusive — og du kan ikke længere gendanne signaturen. Pass-through giver dig bodyen urørt som én enkelt tekststreng: det koster dig ét ekstra modul længere fremme for at parse den, og det giver dig overhovedet muligheden for at verificere noget som helst.
Indsæt nu adressen i Inwista under Mit arbejdsområde → Integrationer, abonnér den på transcript.completed, og kopiér signeringsnøglen, der bliver vist.
Trin 2: verificér signaturen
Højreklik på forbindelsen, der går ud fra webhooken, og tilføj et filter. Funktionen sha256() i Make beregner en HMAC, så snart du giver den en nøgle, så hele kontrollen kan være i ét udtryk — intet kryptomodul, ingen kode.
Betingelse, Text: Equal to:
{{1.headers.x-inwista-signature}}
sha256={{sha256(1.data; "hex"; "your_signing_secret")}}
To detaljer, der ellers koster dig en eftermiddag. Make angiver navnene på indgående headere med små bogstaver, så det hedder x-inwista-signature, ikke skrivemåden med store bogstaver, du ser i vores dokumentation. Og headerens værdi bærer præfikset sha256=, så du skal enten sætte det foran som ovenfor eller fjerne det, før du sammenligner.
Alt, der ikke slipper gennem filteret, stopper ganske enkelt. En usigneret forespørgsel når aldrig frem til modulerne, der laver arbejdet.
Tilføj et JSON → Parse JSON-modul efter filteret, der peger på 1.data. Herfra opfører indholdet sig som et hvilket som helst andet bundle i Make.
Trin 3: hent og levér
Hændelsen indeholder allerede alt, hvad du har brug for:
{
"event": "transcript.completed",
"id": "evt_...",
"timestamp": 1786902819,
"workspaceId": "...",
"project": {
"id": "...",
"name": "board-meeting-august.mp4",
"language": "en",
"durationSeconds": 3184
},
"files": [
{ "format": "srt", "name": "board-meeting-august.srt", "url": "https://...", "expiresAt": 1786989219 }
]
}
Tilføj HTTP → Get a file, og forbind adressen til {{2.files[1].url}}.
Det [1] er ikke en tastefejl. Lister i Make begynder ved 1, og griber du efter [0] af gammel vane, får du en tom værdi i stedet for en fejl — som så sniger sig videre ned gennem flowet og dukker op som en fil på nul byte i Drive tre dage senere.
Adresserne er signerede og gyldige i 24 timer. Hent filen; gem ikke linket.
Hæng derefter det på, som betyder »færdig« for dit team — Google Drive, Dropbox, S3, Slack, et HTTP-kald ind i dit publiceringsværktøj, en række i Airtable eller Notion.
Tre moduler og et filter. Det er hele modtageren, og den håndterer hvert eneste afsluttede job i arbejdsområdet — også de optagelser, dine kolleger uploader i hånden via dashboardet, og som intet pollende scenarie nogensinde ville have fået at vide om.
Trin 4: afsenderen
Andet scenarie. Start med den hændelse, der betyder »der er kommet noget nyt«: et overvågningsmodul til Google Drive eller Dropbox, en Custom webhook fra dit eget publiceringsværktøj, eller en planlagt forespørgsel mod en database. Når du tester, kører du den bare i hånden.
Dens eneste opgave er at producere en offentligt tilgængelig adresse. Tilføj HTTP → Make a request:
- URL —
https://api.inwista.ai/v1/transcriptions - Metode —
POST - Headere —
Authorization:Bearer inw_live_your_key_here - Headere —
Idempotency-Key:{{md5(1.fileUrl)}} - Body-type — Raw, indholdstype JSON
{
"source_url": "{{1.fileUrl}}",
"language": "en",
"diarization": true,
"metadata": { "source": "make", "scenario": "{{1.folderName}}" }
}
Tre felter, det er værd at forstå:
languageer det sprog, der tales i filen, ikke det sprog, du vil have ud. At transskribere på kildesproget er det, der giver præcise tidskoder og ren tekst; oversættelsen kommer bagefter, på den færdige transskribering. Håndterer dit flow flere sprog, forbinder du mappen fra triggeren til dette felt.
diarizationslår markering af, hvem der taler, til. Lad den være slået fra på indhold med kun én stemme — den koster behandlingstid, du ikke har brug for.
metadataer dit. Op til 1 kB med hvad som helst, gengivet ordret ved hver aflæsning og i webhooken — det er sådan, modtageren ved, hvilket scenarie, kursus eller sag en fil hører til, uden at skulle slå noget op.
Læg mærke til, hvad idempotensnøglen udledes af. Udledt af kørslen beskytter den dig mod et nyt forsøg på netop det ene modul. Udledt af filen, som ovenfor, beskytter den dig desuden mod, at den samme optagelse sendes ind to gange fra to forskellige kørsler — hvilket er den klart mest udbredte måde at komme til at betale dobbelt på.
Svaret kommer tilbage med det samme, med status: "processing" og et id. Scenariet slutter der. Det er designet, der virker, ikke designet, der fejler.
Kør oversættelserne parallelt med en Iterator
Én optagelse ud i seks sprog — det er dér, listehåndteringen i Make for alvor gør nytte.
Tilføj et Tools → Set variable med din liste over målsprog i modtageren, når transskriberingen er kommet ind, derefter en Iterator, der løber den igennem, og til sidst ét enkelt HTTP-modul inde i løkken:
POST https://api.inwista.ai/v1/transcriptions/{{2.project.id}}/translate
{ "target_language": "{{4.value}}" }
Hvert kald giver 202 Accepted tilbage. Oversættelsen kører på den færdige transskribering, så tidskoderne passer allerede, og kun teksten ændrer sig. Seks sprog koster seks operationer, og de færdige filer lander gennem den samme webhook, du allerede har bygget.
Når du henter dem, skal du bede om dem udtrykkeligt:
GET /v1/transcriptions/{id}/captions?format=srt&language=no
Sprogparameteren er streng. Beder du om et sprog uden færdig oversættelse, får du en tydelig fejl i stedet for kildesproget i stilhed — hvilket er præcis, hvad du vil have i et flow, ingen holder øje med.
Undertekster i broadcastkvalitet
Rå transskribering er ordret. Undertekstning er et håndværk: linjelængder, læsehastighed, og hvor en sætning brydes over to billeder.
Ét HTTP-modul mere, POST /v1/transcriptions/{id}/enhance, kører transskriberingen gennem den behandling — komprimerer teksten, balancerer linjeskiftene på ny, formaterer dialog og holder blokvarighederne i skak:
{
"settings": {
"maxLinesPerBlock": "2",
"maxCharactersPerLine": 42,
"textCondensation": "smart",
"speakerDialogueFormat": "hyphens",
"gapBetweenBlocks": "broadcasting"
}
}
Derefter serverer endepunkterne til undertekster den forbedrede version automatisk. Intet længere nede i flowet skal ændres.
Når noget går galt: fejlruterne i Make
Højreklik på et hvilket som helst modul, og vælg Add error handler. Make giver dig direktiver, som en almindelig IF-gren ikke kan udtrykke:
- Break — parkerer kørslen i Incomplete Executions, så du kan rette årsagen og køre netop det bundle igen. Sæt den på indsendelsesmodulet.
- Ignore — logger fejlen og går videre. Passer til et leveringstrin, der er rart at have, men ikke kritisk.
- Resume — indsætter en reserveværdi og fortsætter.
- Rollback — ruller bekræftet arbejde tilbage i transaktionelle moduler.
Hver fejl fra Inwista kommer tilbage i den samme struktur:
{ "error": { "code": "insufficient_credits", "message": "..." } }
Forgren på code, aldrig på teksten i beskeden. Koder kommer kun til inden for v1 og bliver aldrig omdøbt; beskeder kan derimod blive formuleret om når som helst.
Hos os bliver webhook-leveringen forsøgt tre gange mere, og et endepunkt, der bliver ved med at fejle, bliver slået fra automatisk med årsagen synlig i dine integrationsindstillinger — en ødelagt modtager viser sig altså som en status, du kan se, i stedet for hændelser, der forsvinder i stilhed.
Undgå at transskribere den samme fil to gange
Triggere på overvågede mapper udløses igen. Filer bliver omdøbt. Nogen uploader det samme en gang til.
Make har sit eget svar på det: Data store. Opret en med kildefilens ID som nøgle, og læg Data store → Get a record ind før HTTP-kaldet i afsenderen, filtrér på, at posten ikke findes, og sæt Add a record efter en vellykket indsendelse.
To operationer for at slippe for at betale for en dobbelt transskribering. Idempotensnøglen dækker nye forsøg på ét modul; data store-en dækker alt det andet.
Følsomme optagelser
Behandler dit flow materiale, du helst ikke vil have, at vi gemmer — patientsamtaler, juridiske optagelser, interne personalemøder — tilføjer du ét felt til indsendelsen:
{
"source_url": "{{1.fileUrl}}",
"language": "en",
"retention": "none"
}
Med retention: "none" slettes kildematerialet, så snart transskriberingen er færdig. Transskribering, undertekster, oversættelser og senere forbedringer fungerer som hidtil — kun lyden og videoen er væk. Der findes også store_media: false, som beholder filen til behandling, men ikke laver afspilningskopier.
I den anden ende af livscyklussen sletter DELETE /v1/transcriptions/{id} alt, der hører til et job, i ét enkelt kald. Et planlagt scenarie, der læser job-ID'er ældre end din opbevaringstid ud af den samme data store og sletter dem, er fire moduler — og det gør din opbevaringspolitik til noget, du kan vise frem i stedet for at beskrive.
Når polling stadig er det rigtige svar
Tre tilfælde taler reelt for det: du kan ikke eksponere en webhook, du har brug for transskriberingen inden for den samme kørsel for at svare på en synkron forespørgsel, eller du kører en engangsomgang over gamle filer, hvor antallet af operationer er ligegyldigt.
Tilføj i så fald et Tools → Sleep-modul og et statustjek mod GET /v1/transcriptions/{id}, og respektér to lofter: Sleep er begrænset til 300 sekunder pr. modul, og en scenariekørsel til 40 minutter. Spørg hvert 20. til 30. sekund i stedet for hvert femte — svaret indeholder et felt progress, der viser, hvor i flowet jobbet faktisk er, så en langsommere løkke giver dig alligevel noget ærligt at vise.
Vil du hellere se det mønster bygget ordentligt ud, bruger n8n-versionen af denne guide polling hele vejen, fordi løkken er gratis på en server, du selv driver.
Faldgruber du før eller siden falder i
Lister begynder ved 1. files[1] er den første fil. files[0] giver tomt tilbage i stedet for at fejle.
Pass-through og parsning er en afvejning. Du kan ikke verificere en signatur mod en body, Make allerede har parset. Pass-through efterfulgt af et Parse JSON-modul er den eneste rigtige rækkefølge.
Grænser for antal kald. 300 læsninger og 60 skrivninger pr. minut pr. nøgle. Rigeligt til normal brug, hurtigt nået hvis du spreder et helt arkiv ud over parallelle scenariekørsler. Kør den slags job i hold.
Kildeadresserne skal kunne nås. API'et undersøger mediefilen, før jobbet tages imod — det er sådan, varighed og pris kendes på forhånd. Et Drive-link, der kræver login, giver unreadable_source, og der bliver ikke opkrævet noget. Brug direkte eller signerede adresser.
Alt tæller med. Sleep-moduler, routere, runder i iteratoren og filtre, der lukker igennem, bruger alle sammen operationer. Føles et scenarie dyrt, så tæl modulerne, før du giver API'et skylden.
Den færdige modtager
Her er skelettet til blueprintet. Importér det, og hæng så din egen webhook og dit leveringsmodul på — og brug forbindelsesstyringen i Make i stedet for at indsætte en nøgle direkte i et modul.
{
"name": "Inwista — transcript receiver",
"flow": [
{
"id": 1,
"module": "gateway:CustomWebHook",
"version": 1,
"parameters": { "hook": 0, "maxResults": 1 },
"mapper": {},
"metadata": { "designer": { "x": 0, "y": 0 } }
},
{
"id": 2,
"module": "json:ParseJSON",
"version": 1,
"parameters": { "type": 0 },
"mapper": { "json": "{{1.data}}" },
"metadata": { "designer": { "x": 300, "y": 0 } }
},
{
"id": 3,
"module": "http:ActionGetFile",
"version": 3,
"parameters": {},
"mapper": { "url": "{{2.files[1].url}}", "serializeUrl": false },
"metadata": { "designer": { "x": 600, "y": 0 } }
}
],
"metadata": {
"instant": true,
"version": 1,
"scenario": { "roundtrips": 1, "maxErrors": 3, "autoCommit": true },
"designer": { "orphans": [] }
}
}
Tre moduler. Varianten med polling havde elleve, og den kostede seks gange så meget at køre.
Hvad det her rent faktisk ændrer
Målet for en automatisering er ikke, hvad den gør, mens du kigger på. Målet er, hvad den gør klokken to om natten til søndag, når en optagelse på halvfems minutter kommer ind, og ingen er vågen.
Et scenarie, der kører i fire minutter pr. fil og brænder operationer af på at stille et spørgsmål, som det allerede kender svaret på, ender som noget, du må holde øje med. En modtager, der vågner, verificerer en signatur, skriver en fil og falder i søvn igen, bliver noget, du glemmer findes — og at glemme, at den findes, er hele pointen.
Dér holder undertekster op med at være en opgave, nogen har ansvaret for. De bliver en egenskab ved hver eneste optagelse, din organisation laver: søgbar, tilgængelig, i tråd med kravene — og ingen behøvede at indkalde til et møde om det.
Klar til at bygge det? Opret en API-nøgle — gratisniveauet er nok til at køre det hele igennem. Den fulde oversigt over endepunkter finder du i API-dokumentationen.