@deewanio/sdk
v0.4.1
Published
Official Deewan server SDK for Node.js, Bun, Deno and edge runtimes: rooms, join links, media tokens, participants, meetings, webinars, polls, breakout rooms, recordings and signed webhooks.
Maintainers
Readme
@deewanio/sdk
The official server SDK for Deewan: video meetings built for the Middle East and North Africa, in Arabic and English, end-to-end encrypted.
Create rooms, send people into meetings, schedule them, moderate them, run webinars, polls and breakout rooms, fetch recordings, and react to everything that happens — from Node.js, Bun, Deno or an edge runtime. Fully typed, no dependencies.
npm install @deewanio/sdkQuick start
import { Deewan } from "@deewanio/sdk";
const deewan = new Deewan({ apiKey: process.env.DEEWAN_API_KEY! });
// A room, and a personal, expiring link into it for one of your users.
const room = await deewan.rooms.create({
name: "Onboarding call",
settings: { admission: "knock", screen_share: "hosts" },
});
const { url } = await deewan.rooms.createJoinLink(room.id, {
name: "Sara Ahmed",
role: "host",
user_id: "user_123", // your own id: the same person keeps the same identity
});
// Send `url` to Sara. It opens Deewan's meeting, or embed it in an <iframe>.Get an API key in the Deewan dashboard under Developers. Keys are server secrets: never ship one to a browser or a mobile app.
Three ways to put people in a meeting
| | Join link | Embedded | Your own interface |
|---|---|---|---|
| You build | Nothing | An <iframe> | The whole UI |
| Call | rooms.createJoinLink() | the same link, framed | rooms.createToken() |
| On the client | — | — | @deewanio/client, @deewanio/react-native, deewan for Flutter |
// Your own interface: a media token for one person (pass the whole response to the client SDK).
const token = await deewan.rooms.createToken(room.id, { name: "Omar", user_id: "user_456" });
// Strict end-to-end encrypted rooms: the client SDK makes the participant's exchange key.
const strictToken = await deewan.rooms.createToken(room.id, { name: "Omar", exchange_key: keyFromTheirDevice });Everything the API does
| Area | Methods |
|---|---|
| Account | me() |
| Rooms | rooms.list() · rooms.all() · create() · retrieve() · update() · delete() · end() |
| Joining | rooms.createJoinLink() · rooms.createToken() |
| Participants | rooms.listParticipants() · muteParticipant() · removeParticipant() · makeCohost() · removeCohost() |
| Waiting room | rooms.listWaiting() · admit() · deny() |
| Webinars | rooms.inviteToSpeak() · rooms.moveToAudience() |
| Scheduled meetings | meetings.list() · create() · retrieve() · update() · cancel() |
| Polls | polls.list() · create() · close() · reopen() · delete() |
| Breakout rooms | breakouts.get() · start() · move() · addRoom() · renameRoom() · removeRoom() · announce() · end() |
| Recordings | recordings.list() · retrieve() · downloadInfo() · download() · delete() |
| Webhooks | webhooks.list() · create() · update() · delete() · test() · deliveries() |
| Verifying webhooks | verifyWebhook(rawBody, signatureHeader, secret) |
// Webinars: a stage and an audience of up to 500.
const webinar = await deewan.rooms.create({ name: "Product launch", settings: { type: "webinar" } });
await deewan.rooms.inviteToSpeak(webinar.id, identity);
// Polls and breakout rooms.
await deewan.polls.create(room.id, { question: "Ship it?", options: ["Yes", "Not yet"], results: "after_vote" });
await deewan.breakouts.start(room.id, { rooms: ["Design", "Engineering"], assign: "auto", duration_seconds: 900 });
// Every room, page by page.
for await (const r of deewan.rooms.all()) console.log(r.name);Webhooks
import { verifyWebhook } from "@deewanio/sdk";
// Pass the raw request body, exactly as received.
const event = await verifyWebhook(rawBody, request.headers.get("deewan-signature"), process.env.DEEWAN_WEBHOOK_SECRET!);
if (event.type === "recording.ready") { /* … */ }Events: room.created · room.updated · room.deleted · room.started · room.finished ·
participant.joined · participant.left · participant.stage_changed · meeting.scheduled ·
meeting.updated · meeting.cancelled · poll.created · poll.closed · breakout.started ·
breakout.ended · recording.ready. Signatures are HMAC-SHA-256, compared in constant time,
and refused when older than five minutes (replay protection).
Errors, retries and timeouts
Every failure is a DeewanError with status, code (e.g. not_found, rate_limited,
insufficient_scope), message and the requestId to quote to support.
const deewan = new Deewan({
apiKey: process.env.DEEWAN_API_KEY!,
timeout: 15_000, // per request, milliseconds
maxRetries: 2, // 429 and 5xx, with backoff; writes are never repeated unless they can't have run
});Security
- Requests go only over HTTPS (
http://is refused except forlocalhost). - Use the narrowest scopes: a service that only sends people into rooms needs
rooms:readandtokens:create. - Issue one join link or token per person, after your app has checked they may join.
- A room token is a secret for that one person: send it only to their client.
Links
- Documentation: https://deewan.io/en/docs
- API reference and OpenAPI 3.1: https://deewan.io/en/docs/reference
- Support: [email protected]
MIT © Deewan
