Transkribering i Make.com: bygg flyten rundt webhooks

En transkriberingsjobb bruker minutter på å bli ferdig. Et Make-scenario faktureres per modulkjøring. Disse to tingene trekker i hver sin retning, og det er nettopp den spenningen denne veiledningen egentlig handler om.


Den nærliggende løsningen — send inn en fil, og så vent, sjekk, vent, sjekk til den er ferdig — koster ingenting på en server du drifter selv. I Make er den ikke gratis. Hver venting og hver statussjekk er en operasjon, og en jobb på fire minutter kan brenne av tretti av dem på å gjøre ingenting annet enn å spørre «er den ferdig snart?».


Vi bygger det derfor motsatt vei. Inwista sier fra til Make i det øyeblikket jobben er ferdig, og scenarioet som fanger opp meldingen, er tre moduler langt.


Til slutt sitter du igjen med:


  1. Et mottakerscenario som våkner når en transkribering er klar
  2. Et avsenderscenario som leverer filer til Inwista og så stopper
  3. Signaturverifisering, slik at mottakeren bare stoler på ekte hendelser
  4. Valgfrie tillegg — oversettelser i parallell, luking av duplikater og en oppryddingsrunde for lagringstid


Alt kjører på det offentlige Inwista API v1 gjennom standard HTTP-modul i Make. Ingen egen app, ingen kode.

Før du starter

Du trenger tre ting:


  • En Make-konto — gratisplanen holder til å bygge dette, selv om taket på antall operasjoner blir trangt i produksjon
  • En API-nøkkel fra Inwista — lag en under Mitt arbeidsområde → API-nøkler. Den begynner med inw_live_
  • Medier API-et kommer til — API-et forventer en offentlig https-adresse, så filer i Dropbox, Google Drive, S3 eller ditt eget publiseringsverktøy trenger en delbar eller signert lenke


Du trenger ikke å drifte et webhook-endepunkt noe sted. Make gir deg adressen.


En merknad om kostnader før du bygger noe som går uten tilsyn: transkribering faktureres med 4 kreditter per påbegynte medieminutt, og belastes når jobben tas imot. Jobber som feiler, refunderes automatisk. Rett scenarioet mot et par korte testfiler før du slipper det løs på arkivet ditt.

Hvorfor oppbygningen er avgjørende her

Begge løsningene virker. De koster bare svært ulikt, og i Make hoper den forskjellen seg opp hver måned.


Et scenario med polling for en jobb som blir ferdig på rundt fire minutter, og som sjekker hvert tjuende sekund, ser omtrent slik ut: én innsending, så tolv runder med venting pluss statussjekk pluss ruter, og til slutt henting og levering. Regn med 39 operasjoner per fil.


Webhook-varianten deler seg i to scenarioer. Avsenderen er en trigger og ett HTTP-kall. Mottakeren er en webhook, en parsing, en henting og en levering. Regn med 6 operasjoner per fil.


Med 200 opptak i måneden blir det 7 800 operasjoner mot 1 200 — forskjellen mellom å måtte oppgradere abonnementet og en avrundingsfeil. Det fjerner også de to feilsituasjonene som rammer pollende scenarioer i produksjon: en kjøring som varer lenge nok til å treffe taket på 40 minutter i Make, og en jobb som står fast og går i loop hele natta uten at noen merker det.


Bygg mottakeren først. Det er den delen som må sitte.

Steg 1: lag mottakeren

Nytt scenario. Legg til en modul, velg Webhooks → Custom webhook, klikk Add, gi den et navn som inwista-transcripts, og kopier adressen Make gir deg.


Før du forlater dialogen, åpne de avanserte innstillingene for webhooken og slå på JSON pass-through.


Dette er innstillingen alle overser, og den er verdt å forstå framfor bare å kopiere. Inwista signerer hver leveranse med en HMAC regnet ut over rå-bytene i forespørselens body. Hvis Make parser JSON-en for deg, er akkurat de bytene borte — rekkefølgen på nøklene og mellomrommene inkludert — og du klarer ikke lenger å gjenskape signaturen. Pass-through gir deg body-en urørt som én enkelt tekststreng: det koster deg én ekstra modul senere for å parse den, og det gir deg i det hele tatt muligheten til å verifisere noe som helst.


Lim nå adressen inn i Inwista under Mitt arbeidsområde → Integrasjoner, abonner den på transcript.completed, og kopier signeringsnøkkelen som vises.

Steg 2: verifiser signaturen

Høyreklikk på forbindelsen som går ut fra webhooken, og legg til et filter. Funksjonen sha256() i Make regner ut en HMAC så snart du gir den en nøkkel, så hele kontrollen får plass i ett uttrykk — ingen kryptomodul, ingen kode.


Betingelse, Text: Equal to:

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

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


To detaljer som ellers koster deg en ettermiddag. Make oppgir navnene på innkommende headere med små bokstaver, så det heter x-inwista-signature, ikke skrivemåten med store bokstaver du ser i dokumentasjonen vår. Og verdien i headeren har prefikset sha256=, så du må enten sette det foran som over, eller fjerne det før du sammenligner.


Alt som ikke slipper gjennom filteret, stopper rett og slett. En usignert forespørsel når aldri fram til modulene som gjør arbeid.


Legg til en JSON → Parse JSON-modul etter filteret, som peker på 1.data. Herfra oppfører innholdet seg som en hvilken som helst annen bundle i Make.

Steg 3: hent og lever

Hendelsen inneholder allerede alt du trenger:

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


Legg til HTTP → Get a file og koble adressen til {{2.files[1].url}}.


Den [1]-en er ingen skrivefeil. Lister i Make begynner på 1, og griper du etter [0] av gammel vane, får du en tom verdi i stedet for en feilmelding — som så sniker seg videre nedover i flyten og dukker opp som en fil på null byte i Drive tre dager senere.


Adressene er signert og gyldige i 24 timer. Hent filen; ikke lagre lenken.


Heng så på det som betyr «ferdig» for teamet ditt — Google Drive, Dropbox, S3, Slack, et HTTP-kall inn i publiseringsverktøyet ditt, en rad i Airtable eller Notion.


Tre moduler og et filter. Det er hele mottakeren, og den håndterer hver eneste fullførte jobb i arbeidsområdet — også opptakene kollegene dine laster opp for hånd i dashbordet, og som ingen pollende scenarioer noen gang ville fått vite om.

Steg 4: avsenderen

Andre scenario. Start med hendelsen som betyr «det har kommet noe nytt»: en overvåkingsmodul for Google Drive eller Dropbox, en Custom webhook fra ditt eget publiseringsverktøy, eller en planlagt spørring mot en database. Når du tester, kjører du den bare for hånd.


Den eneste oppgaven dens er å produsere en offentlig tilgjengelig adresse. Legg til 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, innholdstype JSON


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


Tre felter det er verdt å forstå:


  • language er språket som snakkes i filen, ikke språket du vil ha ut. Å transkribere på kildespråket er det som gir presise tidskoder og ren tekst; oversettelsen kommer etterpå, på den ferdige transkriberingen. Håndterer flyten din flere språk, kobler du mappen fra triggeren til dette feltet.


  • diarization slår på merking av hvem som snakker. La den stå av på innhold med bare én stemme — den koster behandlingstid du ikke trenger.


  • metadata er ditt. Inntil 1 kB med hva du vil, gjengitt ordrett ved hver avlesning og i webhooken — det er slik mottakeren vet hvilket scenario, kurs eller sak en fil hører til, uten å måtte slå opp noe sted.


Merk deg hva idempotensnøkkelen utledes fra. Utledet fra kjøringen beskytter den deg mot et nytt forsøk på akkurat den ene modulen. Utledet fra filen, som over, beskytter den deg i tillegg mot at det samme opptaket sendes inn to ganger fra to ulike kjøringer — som er den klart vanligste måten folk betaler dobbelt ved et uhell.


Svaret kommer tilbake med én gang, med status: "processing" og en id. Scenarioet slutter der. Det er designet som virker, ikke designet som svikter.

Kjør oversettelsene parallelt med en Iterator

Ett opptak ut i seks språk — det er her listehåndteringen i Make virkelig gjør nytte for seg.


Legg til en Tools → Set variable med lista over målspråk i mottakeren etter at transkriberingen har kommet inn, så en Iterator som går gjennom den, og til slutt én enkelt HTTP-modul inne i løkka:

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

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


Hvert kall gir 202 Accepted tilbake. Oversettelsen kjøres på den ferdige transkriberingen, så tidskodene stemmer allerede og bare teksten endrer seg. Seks språk koster seks operasjoner, og de ferdige filene lander gjennom den samme webhooken du allerede har bygd.


Når du henter dem, må du be om dem uttrykkelig:

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


Språkparameteren er streng. Ber du om et språk uten ferdig oversettelse, får du en tydelig feilmelding i stedet for kildespråket i det stille — som er akkurat det du vil ha i en flyt ingen følger med på.

Undertekster i kringkastingskvalitet

Rå transkribering er ordrett. Teksting er et håndverk: linjelengder, lesehastighet, og hvor en setning brekkes over to bilder.


Én HTTP-modul til, POST /v1/transcriptions/{id}/enhance, kjører transkriberingen gjennom den behandlingen — komprimerer teksten, balanserer linjeskiftene på nytt, formaterer dialog og holder blokkvarighetene i sjakk:

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


Etterpå serverer endepunktene for undertekster den forbedrede versjonen automatisk. Ingenting lenger ned i flyten trenger å endres.

Når noe går galt: feilrutene i Make

Høyreklikk på en hvilken som helst modul og velg Add error handler. Make gir deg direktiver som en vanlig IF-gren ikke får uttrykt:


  • Break — parkerer kjøringen i Incomplete Executions, så du kan rette årsaken og kjøre akkurat den bundlen på nytt. Sett denne på innsendingsmodulen.
  • Ignore — logger feilen og går videre. Passer på et leveringssteg som er greit å ha, men ikke kritisk.
  • Resume — setter inn en reserveverdi og fortsetter.
  • Rollback — reverserer bekreftet arbeid i transaksjonelle moduler.


Hver feil fra Inwista kommer tilbake i samme struktur:

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


Forgren på code, aldri på teksten i meldingen. Koder kommer bare i tillegg innenfor v1 og blir aldri døpt om; meldinger kan derimot bli formulert på nytt når som helst.


Hos oss forsøkes webhook-leveringen tre ganger til, og et endepunkt som fortsetter å feile, blir slått av automatisk med årsaken synlig i integrasjonsinnstillingene dine — en ødelagt mottaker viser seg altså som en status du kan se, i stedet for hendelser som forsvinner i stillhet.

Ikke transkriber samme fil to ganger

Triggere på overvåkede mapper utløses på nytt. Filer får nye navn. Noen laster opp det samme en gang til.


Make har et eget svar på dette: Data store. Lag en med ID-en til kildefilen som nøkkel, og legg inn Data store → Get a record før HTTP-kallet i avsenderen, filtrer på at oppføringen ikke finnes, og sett Add a record etter en vellykket innsending.


To operasjoner for å slippe å betale for en dobbel transkribering. Idempotensnøkkelen dekker nye forsøk på én modul; data store-en dekker alt det andre.

Sensitive opptak

Behandler flyten din materiale du helst ikke vil at vi skal ta vare på — pasientsamtaler, juridiske opptak, interne allmøter — legger du til ett felt i innsendingen:

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


Med retention: "none" slettes kildematerialet så snart transkriberingen er ferdig. Transkribering, undertekster, oversettelser og senere forbedringer fungerer som før — bare lyden og videoen er borte. Det finnes også store_media: false, som beholder filen til behandling, men ikke lager avspillingskopier.


I den andre enden av livsløpet sletter DELETE /v1/transcriptions/{id} alt som hører til en jobb, i ett eneste kall. Et planlagt scenario som leser ut jobb-ID-er eldre enn lagringstiden din fra den samme data store-en og sletter dem, er fire moduler — og det gjør lagringsrutinen din til noe du kan vise fram i stedet for å beskrive.

Når polling likevel er riktig svar

Tre tilfeller taler virkelig for det: du kan ikke eksponere en webhook, du trenger transkriberingen inne i samme kjøring for å svare på en synkron forespørsel, eller du kjører en engangsjobb over gamle filer der antallet operasjoner ikke spiller noen rolle.


Legg i så fall til en Tools → Sleep-modul og en statussjekk mot GET /v1/transcriptions/{id}, og respekter to tak: Sleep er begrenset til 300 sekunder per modul, og en scenariokjøring til 40 minutter. Spør hvert 20. til 30. sekund i stedet for hvert femte — svaret har et felt progress som viser hvor i flyten jobben faktisk er, så en tregere løkke gir deg likevel noe ærlig å vise fram.


Vil du heller se det mønsteret bygd ut ordentlig, bruker n8n-versjonen av denne veiledningen polling hele veien, fordi løkka er gratis på en server du drifter selv.

Fallgruver du før eller siden går i

Lister begynner på 1. files[1] er den første filen. files[0] gir tomt tilbake i stedet for å feile.


Pass-through og parsing er en avveining. Du kan ikke verifisere en signatur mot en body Make allerede har parset. Pass-through etterfulgt av en Parse JSON-modul er den eneste riktige rekkefølgen.


Grenser for antall kall. 300 lesinger og 60 skrivinger per minutt per nøkkel. Romslig til vanlig bruk, fort nådd hvis du sprer et helt arkiv utover parallelle scenariokjøringer. Kjør slike jobber i puljer.


Kildeadressene må være tilgjengelige. API-et undersøker mediefilen før jobben tas imot — det er slik varighet og pris er kjent på forhånd. En Drive-lenke som krever innlogging, gir unreadable_source, og ingenting blir belastet. Bruk direkte eller signerte adresser.


Alt teller. Sleep-moduler, rutere, runder i iteratoren og filtre som slipper gjennom, bruker alle sammen operasjoner. Føles et scenario dyrt, tell modulene før du skylder på API-et.

Den ferdige mottakeren

Her er skjelettet til blueprinten. Importer det, og heng så på din egen webhook og leveringsmodul — og bruk tilkoblingslageret i Make i stedet for å lime en nøkkel rett inn 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 hadde elleve, og kostet seks ganger så mye å kjøre.

Hva dette faktisk endrer

Målet på en automatisering er ikke hva den gjør mens du ser på. Målet er hva den gjør klokka to natt til søndag, når et opptak på nitti minutter kommer inn og ingen er våkne.


Et scenario som går i fire minutter per fil og brenner operasjoner på å stille et spørsmål det allerede vet svaret på, ender opp som noe du må følge med på. En mottaker som våkner, verifiserer en signatur, skriver en fil og legger seg igjen, blir noe du glemmer at finnes — og det å glemme at den finnes, er hele poenget.


Da slutter undertekster å være en oppgave noen har ansvaret for. De blir en egenskap ved hvert eneste opptak organisasjonen din lager: søkbart, tilgjengelig, i tråd med kravene — og ingen måtte innkalle til et møte om det.


Klar til å bygge det? Lag en API-nøkkel — gratisnivået holder til å kjøre hele dette løpet. Den fullstendige oversikten over endepunkter finner du i API-dokumentasjonen.