Transkribering i Make.com: bygg flödet kring webhooks

Ett transkriberingsjobb tar minuter på sig att bli klart. Ett Make-scenario debiteras per modulkörning. De två sakerna drar åt var sitt håll, och det är just den spänningen den här guiden egentligen handlar om.


Den självklara lösningen — skicka in en fil och sedan vänta, kolla, vänta, kolla tills den är klar — kostar ingenting på en server du driftar själv. I Make är den inte gratis. Varje väntan och varje statuskoll är en operation, och ett jobb på fyra minuter kan bränna trettio av dem på att inte göra något annat än att fråga ”är den klar snart?”.


Vi bygger det därför tvärtom. Inwista säger till Make i samma stund som arbetet är klart, och scenariot som fångar upp meddelandet är tre moduler långt.


Till slut har du:


  1. Ett mottagarscenario som vaknar när en transkribering är klar
  2. Ett avsändarscenario som lämnar över filer till Inwista och sedan stannar
  3. Signaturverifiering, så att mottagaren bara litar på äkta händelser
  4. Valfria tillägg — översättningar parallellt, rensning av dubbletter och en uppstädning av lagringstiden


Allt körs på det publika Inwista API v1 genom standardmodulen HTTP i Make. Ingen egen app, ingen kod.

Innan du börjar

Du behöver tre saker:


  • Ett Make-konto — gratisplanen räcker för att bygga det här, även om taket för antal operationer blir snålt i produktion
  • En API-nyckel från Inwista — skapa en under Min arbetsyta → API-nycklar. Den börjar med inw_live_
  • Media som API:et kommer åt — API:et förväntar sig en publik https-adress, så filer i Dropbox, Google Drive, S3 eller ditt eget publiceringsverktyg behöver en delbar eller signerad länk


Du behöver inte drifta någon webhook-slutpunkt någonstans. Make ger dig adressen.


En notering om kostnaden innan du bygger något som går utan tillsyn: transkribering debiteras med 4 krediter per påbörjad mediaminut, och dras när jobbet tas emot. Jobb som misslyckas återbetalas automatiskt. Rikta scenariot mot ett par korta testfiler innan du släpper lös det på ditt arkiv.

Varför upplägget spelar roll här

Båda lösningarna fungerar. De kostar bara väldigt olika mycket, och i Make växer den skillnaden varje månad.


Ett scenario med polling för ett jobb som blir klart på ungefär fyra minuter, och som kollar var tjugonde sekund, ser ungefär ut så här: en inskickning, sedan tolv varv med väntan plus statuskoll plus router, och till sist hämtning och leverans. Räkna med 39 operationer per fil.


Webhook-varianten delas upp i två scenarier. Avsändaren är en trigger och ett HTTP-anrop. Mottagaren är en webhook, en parsning, en hämtning och en leverans. Räkna med 6 operationer per fil.


Med 200 inspelningar i månaden blir det 7 800 operationer mot 1 200 — skillnaden mellan att behöva uppgradera abonnemanget och ett avrundningsfel. Det tar också bort de två felsituationer som drabbar pollande scenarier i produktion: en körning som pågår tillräckligt länge för att slå i taket på 40 minuter i Make, och ett jobb som fastnat och loopar hela natten utan att någon märker det.


Bygg mottagaren först. Det är den delen som måste sitta.

Steg 1: skapa mottagaren

Nytt scenario. Lägg till en modul, välj Webhooks → Custom webhook, klicka på Add, ge den ett namn som inwista-transcripts och kopiera adressen Make ger dig.


Innan du lämnar dialogen, öppna webhookens avancerade inställningar och slå på JSON pass-through.


Det här är inställningen som alla missar, och den är värd att förstå snarare än att bara kopiera. Inwista signerar varje leverans med en HMAC som räknas ut över råa bytes i förfrågans body. Om Make parsar JSON:en åt dig är precis de byten borta — inklusive ordningen på nycklarna och blankstegen — och du kan inte längre återskapa signaturen. Pass-through ger dig bodyn orörd som en enda textsträng: det kostar dig en extra modul längre fram för att parsa den, och det ger dig överhuvudtaget möjligheten att verifiera något alls.


Klistra nu in adressen i Inwista under Min arbetsyta → Integrationer, prenumerera den på transcript.completed och kopiera signeringsnyckeln som visas.

Steg 2: verifiera signaturen

Högerklicka på kopplingen som går ut från webhooken och lägg till ett filter. Funktionen sha256() i Make räknar ut en HMAC så snart du ger den en nyckel, så hela kontrollen ryms i ett enda uttryck — ingen kryptomodul, ingen kod.


Villkor, Text: Equal to:

{{1.headers.x-inwista-signature}}

sha256={{sha256(1.data; "hex"; "your_signing_secret")}}


Två detaljer som annars kostar dig en eftermiddag. Make anger namnen på inkommande headers med små bokstäver, så det heter x-inwista-signature, inte skrivsättet med stora bokstäver som du ser i vår dokumentation. Och headerns värde bär prefixet sha256=, så du måste antingen sätta det framför som ovan eller ta bort det innan du jämför.


Allt som inte klarar filtret stannar helt enkelt. En osignerad förfrågan når aldrig fram till modulerna som gör jobbet.


Lägg till en JSON → Parse JSON-modul efter filtret, som pekar på 1.data. Härifrån beter sig innehållet som vilken annan bundle som helst i Make.

Steg 3: hämta och leverera

Händelsen innehåller redan allt du behöver:

{
  "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 }
  ]
}


Lägg till HTTP → Get a file och koppla adressen till {{2.files[1].url}}.


Den där [1] är inget skrivfel. Listor i Make börjar på 1, och tar du [0] av gammal vana får du ett tomt värde i stället för ett fel — som sedan smyger vidare nedåt i flödet och dyker upp som en fil på noll byte i Drive tre dagar senare.


Adresserna är signerade och giltiga i 24 timmar. Hämta filen; spara inte länken.


Häng sedan på det som betyder ”klart” för ditt team — Google Drive, Dropbox, S3, Slack, ett HTTP-anrop in i ditt publiceringsverktyg, en rad i Airtable eller Notion.


Tre moduler och ett filter. Det är hela mottagaren, och den hanterar varje avslutat jobb i arbetsytan — även inspelningarna som dina kollegor laddar upp för hand i instrumentpanelen, och som inget pollande scenario någonsin hade fått veta om.

Steg 4: avsändaren

Andra scenariot. Börja med händelsen som betyder ”det har kommit något nytt”: en bevakningsmodul för Google Drive eller Dropbox, en Custom webhook från ditt eget publiceringsverktyg, eller en schemalagd fråga mot en databas. När du testar kör du den bara för hand.


Dess enda uppgift är att producera en publikt åtkomlig adress. Lägg till HTTP → Make a request:


  • URL — https://api.inwista.ai/v1/transcriptions
  • Metod — POST
  • Headers — Authorization: Bearer inw_live_your_key_here
  • Headers — Idempotency-Key: {{md5(1.fileUrl)}}
  • Body-typ — Raw, innehållstyp JSON


{
  "source_url": "{{1.fileUrl}}",
  "language": "en",
  "diarization": true,
  "metadata": { "source": "make", "scenario": "{{1.folderName}}" }
}


Tre fält som är värda att förstå:


  • language är språket som talas i filen, inte språket du vill få ut. Att transkribera på källspråket är det som ger exakta tidskoder och ren text; översättningen kommer efteråt, på den färdiga transkriberingen. Hanterar ditt flöde flera språk kopplar du mappen från triggern till det här fältet.


  • diarization slår på markering av vem som talar. Låt den vara av på innehåll med bara en röst — den kostar bearbetningstid du inte behöver.


  • metadata är ditt. Upp till 1 kB med vad du vill, återgivet ordagrant vid varje avläsning och i webhooken — det är så mottagaren vet vilket scenario, vilken kurs eller vilket ärende en fil hör till, utan att behöva slå upp något.


Lägg märke till vad idempotensnyckeln härleds från. Härledd från körningen skyddar den dig mot ett nytt försök på just den ena modulen. Härledd från filen, som ovan, skyddar den dig dessutom mot att samma inspelning skickas in två gånger från två olika körningar — vilket är det klart vanligaste sättet att betala dubbelt av misstag.


Svaret kommer tillbaka direkt, med status: "processing" och ett id. Scenariot slutar där. Det är designen som fungerar, inte designen som fallerar.

Kör översättningarna parallellt med en Iterator

En inspelning ut i sex språk — det är där listhanteringen i Make verkligen gör nytta.


Lägg till en Tools → Set variable med din lista över målspråk i mottagaren när transkriberingen har kommit in, sedan en Iterator som går igenom den, och till sist en enda HTTP-modul inuti loopen:

POST https://api.inwista.ai/v1/transcriptions/{{2.project.id}}/translate

{ "target_language": "{{4.value}}" }


Varje anrop ger 202 Accepted tillbaka. Översättningen körs på den färdiga transkriberingen, så tidskoderna stämmer redan och bara texten ändras. Sex språk kostar sex operationer, och de färdiga filerna landar via samma webhook som du redan har byggt.


När du hämtar dem måste du be om dem uttryckligen:

GET /v1/transcriptions/{id}/captions?format=srt&language=no


Språkparametern är strikt. Ber du om ett språk utan färdig översättning får du ett tydligt fel i stället för källspråket i tysthet — vilket är precis vad du vill ha i ett flöde som ingen bevakar.

Undertexter med broadcastkvalitet

Rå transkribering är ordagrann. Undertextning är ett hantverk: radlängder, läshastighet, och var en mening bryts över två rutor.


Ytterligare en HTTP-modul, POST /v1/transcriptions/{id}/enhance, kör transkriberingen genom den behandlingen — komprimerar texten, balanserar om radbrytningarna, formaterar dialog och håller blocklängderna i schack:

{
  "settings": {
    "maxLinesPerBlock": "2",
    "maxCharactersPerLine": 42,
    "textCondensation": "smart",
    "speakerDialogueFormat": "hyphens",
    "gapBetweenBlocks": "broadcasting"
  }
}


Därefter serverar slutpunkterna för undertexter den förbättrade versionen automatiskt. Ingenting längre ned i flödet behöver ändras.

När något går fel: felvägarna i Make

Högerklicka på vilken modul som helst och välj Add error handler. Make ger dig direktiv som en vanlig IF-gren inte kan uttrycka:


  • Break — parkerar körningen i Incomplete Executions, så att du kan rätta orsaken och köra just den bundlen igen. Sätt den här på inskickningsmodulen.
  • Ignore — loggar felet och går vidare. Passar ett leveranssteg som är bra att ha men inte kritiskt.
  • Resume — sätter in ett reservvärde och fortsätter.
  • Rollback — återställer bekräftat arbete i transaktionella moduler.


Varje fel från Inwista kommer tillbaka i samma struktur:

{ "error": { "code": "insufficient_credits", "message": "..." } }


Förgrena på code, aldrig på texten i meddelandet. Koder tillkommer bara inom v1 och byter aldrig namn; meddelanden kan däremot formuleras om när som helst.


Hos oss görs tre nya försök att leverera webhooken, och en slutpunkt som fortsätter att fallera stängs av automatiskt med orsaken synlig i dina integrationsinställningar — en trasig mottagare syns alltså som en status du kan se, i stället för händelser som försvinner i tysthet.

Transkribera inte samma fil två gånger

Triggers på bevakade mappar utlöses igen. Filer byter namn. Någon laddar upp samma sak en gång till.


Make har ett eget svar på det: Data store. Skapa en med källfilens ID som nyckel, och lägg in Data store → Get a record före HTTP-anropet i avsändaren, filtrera på att posten inte finns, och sätt Add a record efter en lyckad inskickning.


Två operationer för att slippa betala för en dubbel transkribering. Idempotensnyckeln täcker nya försök på en modul; data store-n täcker allt annat.

Känsliga inspelningar

Behandlar ditt flöde material som du helst inte vill att vi sparar — patientsamtal, juridiska inspelningar, interna allmöten — lägger du till ett fält i inskickningen:

{
  "source_url": "{{1.fileUrl}}",
  "language": "en",
  "retention": "none"
}


Med retention: "none" raderas källmaterialet så snart transkriberingen är klar. Transkribering, undertexter, översättningar och senare förbättringar fungerar precis som förut — bara ljudet och videon är borta. Det finns också store_media: false, som behåller filen för bearbetning men inte skapar några uppspelningskopior.


I andra änden av livscykeln raderar DELETE /v1/transcriptions/{id} allt som hör till ett jobb, i ett enda anrop. Ett schemalagt scenario som läser ut jobb-ID:n äldre än din lagringstid ur samma data store och raderar dem är fyra moduler — och det gör din lagringspolicy till något du kan visa upp i stället för att beskriva.

När polling ändå är rätt svar

Tre fall talar verkligen för det: du kan inte exponera en webhook, du behöver transkriberingen inom samma körning för att svara på en synkron förfrågan, eller du kör en engångsomgång över gamla filer där antalet operationer inte spelar någon roll.


Lägg i så fall till en Tools → Sleep-modul och en statuskoll mot GET /v1/transcriptions/{id}, och respektera två tak: Sleep är begränsad till 300 sekunder per modul, och en scenariokörning till 40 minuter. Fråga var 20:e till 30:e sekund i stället för var femte — svaret innehåller ett fält progress som visar var i flödet jobbet faktiskt är, så en långsammare loop ger dig ändå något ärligt att visa.


Vill du hellre se det mönstret utbyggt ordentligt använder n8n-versionen av den här guiden polling hela vägen, eftersom loopen är gratis på en server du driftar själv.

Fallgropar du förr eller senare trillar i

Listor börjar på 1. files[1] är den första filen. files[0] ger tomt tillbaka i stället för att fallera.


Pass-through och parsning är en avvägning. Du kan inte verifiera en signatur mot en body som Make redan har parsat. Pass-through följt av en Parse JSON-modul är den enda rätta ordningen.


Gränser för antal anrop. 300 läsningar och 60 skrivningar per minut och nyckel. Generöst för normal användning, snabbt uppnått om du sprider ut ett helt arkiv över parallella scenariokörningar. Kör sådana jobb i omgångar.


Källadresserna måste gå att nå. API:et undersöker mediefilen innan jobbet tas emot — det är så längd och pris är kända på förhand. En Drive-länk som kräver inloggning ger unreadable_source, och ingenting debiteras. Använd direkta eller signerade adresser.


Allt räknas. Sleep-moduler, routrar, varv i iteratorn och filter som släpper igenom förbrukar allihop operationer. Känns ett scenario dyrt, räkna modulerna innan du skyller på API:et.

Den färdiga mottagaren

Här är stommen till blueprinten. Importera den och häng sedan på din egen webhook och leveransmodul — och använd anslutningshanteringen i Make i stället för att klistra in en nyckel rakt i en 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 hade elva, och kostade sex gånger så mycket att köra.

Vad det här faktiskt förändrar

Måttet på en automatisering är inte vad den gör medan du tittar på. Måttet är vad den gör klockan två på natten mot söndag, när en inspelning på nittio minuter kommer in och ingen är vaken.


Ett scenario som går i fyra minuter per fil och bränner operationer på att ställa en fråga som det redan vet svaret på blir något du till slut måste hålla ett öga på. En mottagare som vaknar, verifierar en signatur, skriver en fil och somnar om blir något du glömmer att den finns — och att glömma bort den är hela poängen.


Då slutar undertexter att vara en uppgift som någon ansvarar för. De blir en egenskap hos varje inspelning din organisation gör: sökbar, tillgänglig, i linje med kraven — och ingen behövde kalla till ett möte om saken.


Redo att bygga det? Skapa en API-nyckel — gratisnivån räcker för att köra igenom hela det här. Den fullständiga slutpunktsreferensen hittar du i API-dokumentationen.