Ontwikkelaars
Bouw op Mets
Een REST API en ondertekende webhooks voor vergaderingen, opnames, transcripties en AI-samenvattingen. Uw gegevens blijven in de EU.
Quickstart
Van nul tot een vergadering in drie stappen
Geen SDK nodig. Gewoon HTTPS en JSON.
- 1
Een API-sleutel maken
Open Instellingen, Ontwikkelaars, en maak een sleutel met alleen de rechten die u nodig hebt. Hij wordt één keer getoond.
- 2
De API aanroepen
Stuur de sleutel als Bearer-token mee. Maak vergaderingen, toon opnames, haal transcripties en samenvattingen op.
- 3
Naar gebeurtenissen luisteren
Voeg een webhook-endpoint toe en reageer wanneer een vergadering eindigt of een transcriptie gereed is, of raadpleeg de gebeurtenissenfeed.
curl -X POST https://mets.ulewicz.space/api/v1/public/meetings \
-H "Authorization: Bearer $METS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Weekly sync",
"scheduled_at": "2026-11-03T09:00:00+01:00",
"duration_minutes": 30,
"settings": { "waiting_room": true, "transcription_auto": true }
}'
# -> 201 { "id": "…", "code": "abc-defg-hjk", "join_url": "https://mets.ulewicz.space/m/abc-defg-hjk", … }curl https://mets.ulewicz.space/api/v1/public/meetings/abc-defg-hjk/recordings \
-H "Authorization: Bearer $METS_API_KEY"
# -> { "data": [ { "id": "…", "kind": "video", "status": "ready",
# "duration_seconds": 1834, "download_url": "https://…" } ] }Webhooks
Weet het op het moment dat er iets gebeurt
Elke levering is een ondertekende HTTPS-POST. Mislukte leveringen worden met exponentiële uitstel opnieuw geprobeerd, in totaal vijf pogingen.
meeting.startedDe eerste deelnemer is binnengekomen en de vergadering is live.meeting.endedDe vergadering is afgelopen.recording.readyEen opname is verwerkt en kan worden gedownload.transcript.readyDe transcriptie is compleet.summary.readyDe AI-samenvatting is beschikbaar.registration.createdIemand heeft zich geregistreerd voor een van uw webinars.
POST https://your-server.example/webhooks/mets
X-Mets-Event: meeting.ended
X-Mets-Delivery: 7c0f…
X-Mets-Timestamp: 1790000000
X-Mets-Signature: sha256=9f2b…
{
"id": "evt_1042",
"type": "meeting.ended",
"created_at": "2026-11-03T09:31:07Z",
"data": { "meeting": { "id": "…", "code": "abc-defg-hjk", "title": "Weekly sync", "status": "ended" } }
}Verifieer elk verzoek
Mets ondertekent de body met het geheim van uw endpoint: X-Mets-Signature is sha256= gevolgd door de HMAC-SHA256 van de tijdstempel, een punt en de ruwe body. Vergelijk in constante tijd en weiger tijdstempels die ouder zijn dan vijf minuten.
import crypto from "node:crypto";
// Express: use express.raw({ type: "application/json" }) so you get the exact bytes.
export function verify(rawBody, headers, secret) {
const ts = headers["x-mets-timestamp"];
const expected =
"sha256=" + crypto.createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest("hex");
const given = headers["x-mets-signature"] ?? "";
const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300; // reject replays
return (
fresh &&
given.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected))
);
}import hashlib, hmac, time
def verify(raw_body: bytes, headers: dict, secret: str) -> bool:
ts = headers["X-Mets-Timestamp"]
mac = hmac.new(secret.encode(), ts.encode() + b"." + raw_body, hashlib.sha256).hexdigest()
expected = "sha256=" + mac
fresh = abs(time.time() - int(ts)) < 300 # reject replays
return fresh and hmac.compare_digest(expected, headers["X-Mets-Signature"])Automatisering
Zapier, Make en n8n zonder code
Polling-triggers plus uitgaande webhooks – dezelfde events die u in de app ziet. Plus meldingen in Slack en Teams.
Polling-triggers
GET /api/v1/public/triggers/{event}?since= geeft events na uw laatste cursor. Zonder since krijgt u de meest recente – handig voor voorbeelddata.
meeting.startedmeeting.endedrecording.readytranscript.readysummary.readyregistration.created
- Zapier: app in integrations/zapier (API-sleutelauthenticatie, 6 triggers, acties: vergadering aanmaken, deelnemer registreren).
- n8n: nodepakket integrations/n8n (Mets + Mets Trigger).
- Make: HTTP-module + ondertekende uitgaande webhooks.
- Slack en Teams: Instellingen → Integraties → Kanaalmeldingen.
# newest first (first poll / sample), then follow next_cursor
curl -s -H "Authorization: Bearer $METS_API_KEY" \
"https://mets.ulewicz.space/api/v1/public/triggers/summary.ready?limit=5"
curl -s -H "Authorization: Bearer $METS_API_KEY" \
"https://mets.ulewicz.space/api/v1/public/triggers/registration.created?since=evt_1234&slug=my-webinar"MCP
Vergaderingen voor AI-agents (MCP)
Een Model Context Protocol-server (Streamable HTTP). Claude, Cursor en andere agents lezen transcripten, doorzoeken vergaderingen en plannen nieuwe in.
Tools
Endpoint: POST https://mets.ulewicz.space/api/v1/mcp. Resources: mets://meetings/{id}/transcript en /summary.
list_meetingsVergaderingen weergeven (statusfilter).get_meetingVergaderdetails op id of code.get_transcriptTranscript als platte tekst, optioneel vertaald.get_summaryAI-samenvatting: TL;DR, besluiten, actiepunten.search_contentZoeken in volledige tekst door transcripten en chat.ask_meetingsVraag in natuurlijke taal (RAG) met bronvermelding.list_tasksVergadertaken en trackerlinks.create_meetingDirecte vergadering met een deelnamelink.schedule_meetingEen vergadering inplannen voor een bepaald tijdstip.
Authenticeer met een API-sleutel (Instellingen → Ontwikkelaar). De tools die u ziet hangen af van de scopes van de sleutel.
{
"mcpServers": {
"mets": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"https://mets.ulewicz.space/api/v1/mcp",
"--header", "Authorization: Bearer ${METS_API_KEY}"
],
"env": { "METS_API_KEY": "mets_sk_..." }
}
}
}{
"mcpServers": {
"mets": {
"url": "https://mets.ulewicz.space/api/v1/mcp",
"headers": { "Authorization": "Bearer mets_sk_..." }
}
}
}claude mcp add --transport http mets https://mets.ulewicz.space/api/v1/mcp \
--header "Authorization: Bearer mets_sk_..."curl -s https://mets.ulewicz.space/api/v1/mcp \
-H "Authorization: Bearer $METS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"ask_meetings","arguments":{"question":"What did we decide about pricing?"}}}'Insluiten
Plaats een Mets-vergadering in uw product
Een frameworkonafhankelijke SDK toont de ruimte in een iframe en communiceert met uw pagina via een klein, geversioneerd postMessage-protocol.
- 1
Sta uw origins toe
Alleen pagina's op de origins die u opgeeft mogen de ruimte insluiten. De lijst wordt door de browser afgedwongen via CSP frame-ancestors.
- 2
Koppel de SDK
Laad de script-tag, de ES-module of de React-component en wijs naar een vergadercode of een embed-token.
- 3
Geef tokens uit op uw server
Maak met uw API-sleutel een kortlevend token voor een gast met naam, zodat de code en de sleutel nooit de browser bereiken.
curl -X PUT https://mets.ulewicz.space/api/v1/public/meetings/abc-defg-hjk/embed-origins \
-H "Authorization: Bearer mets_sk_..." \
-H "Content-Type: application/json" \
-d '{ "origins": ["https://app.example.com", "https://*.example.com"] }'<div id="meeting" style="height: 640px"></div>
<script src="https://mets.ulewicz.space/embed/mets-embed.js"></script>
<script>
const meeting = MetsEmbed.MetsMeeting.create({
container: "#meeting",
meetingCode: "abc-defg-hjk",
name: "Anna", // pre-filled guest name
locale: "en",
theme: "dark",
features: { chat: true, participants: true },
onEvent: (e) => console.log(e.type, e),
});
meeting.on("joined", (e) => console.log("in the room as", e.participant.name));
meeting.on("participant-count", (e) => console.log(e.count, "people"));
document.querySelector("#mute").onclick = () => meeting.mute();
</script>npm install @mets/embed
import { MetsMeeting } from "@mets/embed";
const meeting = MetsMeeting.create({
container: document.getElementById("meeting")!,
joinToken, // from your server, see below
onEvent: (e) => { if (e.type === "left") showThanks(); },
});npm install @mets/embed @mets/embed-react
import { MetsMeeting } from "@mets/embed-react";
export function Room({ joinToken }: { joinToken: string }) {
const ref = useRef<MetsMeetingHandle>(null);
return (
<div style={{ height: 640 }}>
<MetsMeeting ref={ref} joinToken={joinToken} locale="en" onEvent={(e) => console.log(e)} />
<button onClick={() => ref.current?.mute()}>Mute</button>
</div>
);
}# server side — the browser never sees the meeting code or your API key
curl -X POST https://mets.ulewicz.space/api/v1/public/embed/tokens \
-H "Authorization: Bearer mets_sk_..." \
-H "Content-Type: application/json" \
-d '{ "meeting": "abc-defg-hjk", "name": "Anna Kowalska", "ttl_seconds": 600,
"features": { "chat": false } }'
# 201
{ "token": "mets_et_eyJj...", "expires_at": "2026-10-09T12:10:00Z",
"embed_url": "https://mets.ulewicz.space/en/embed/mets_et_eyJj...", "embeddable": true }Events (iframe naar pagina)
readyDe ingesloten pagina is gestart en accepteert commando's.joinedDe gast is de ruimte binnengekomen (deelnemer- en vergaderinfo).leftDe gast is vertrokken, verwijderd of de vergadering is beëindigd (met reden).participant-countAantal personen dat nu in de ruimte is.recordingOpname gestart of gestopt (active, mode).mediaDe lokale microfoon of camera is aan- of uitgezet.errorDe vergadering is niet beschikbaar (niet gevonden, beëindigd, geannuleerd).
Commando's (pagina naar iframe)
muteDemp de lokale microfoon, of de camera met kind: "video".unmuteZet de microfoon (of camera) weer aan.leaveVerlaat de vergadering.toggleChatOpen of sluit het chatpaneel.setThemeWissel tussen licht, donker en systeemthema.
// iframe -> host page (posted to exactly one validated origin)
{ source: "mets-embed", v: 1, dir: "event", type: "joined",
participant: { identity, name, role }, meeting: { code, title } }
// host page -> iframe (accepted only from an allow-listed origin)
{ source: "mets-embed", v: 1, dir: "command", type: "setTheme", theme: "dark" }Standaard vergrendeld
Zonder toegestane origins kan niets de ruimte insluiten. Events worden naar één gevalideerde origin gestuurd, commando's worden alleen daarvan geaccepteerd en embed-tokens zijn ondertekend, verlopen snel en leggen de gastnaam vast.
Referentie
Alles wat u nodig hebt, niets wat u niet nodig hebt
Twaalf endpoints dekken vergaderingen, opnames, transcripties, samenvattingen, webinarregistraties en gebeurtenissen.
- GET
/me— - GET
/meetingsmeetings:read - POST
/meetingsmeetings:write - GET
/meetings/{id}meetings:read - PATCH
/meetings/{id}meetings:write - DELETE
/meetings/{id}meetings:write - GET
/meetings/{id}/participantsmeetings:read - GET
/meetings/{id}/recordingsrecordings:read - GET
/meetings/{id}/transcripttranscripts:read - GET
/meetings/{id}/summarytranscripts:read - POST
/webinars/{slug}/registrationswebinars:write - GET
/eventsmeetings:read
API-sleutels met beperkte rechten
Authorization: Bearer mets_sk_…. Sleutels dragen alleen de rechten die u verleent en kunnen worden beperkt tot een organisatie, verlopen of op elk moment worden ingetrokken.
Eerlijke rate limits
120 verzoeken per minuut en pieken van 20 per seconde per sleutel. Elk antwoord bevat X-RateLimit-headers.
OpenAPI 3
Een volledig machineleesbaar schema en een interactieve console om verzoeken uit te proberen.
API inbegrepen in Business
De Public API en webhooks zijn onderdeel van het abonnement Business, zonder kosten per verzoek. Hebt u hogere limieten of een overeenkomst op maat nodig? Schrijf ons.
Lever vandaag nog uw eerste integratie op
Maak een account, genereer een sleutel en doe binnen enkele minuten uw eerste verzoek.