MDH API Documentation
Everything you need to publish events, register endpoints, verify signatures, and replay deliveries — plus downloadable specs and an AI assistant that knows this API end to end.
MDH is a webhook delivery and monitoring platform. Send events in and fan them out to customer endpoints with signed, retried, observable delivery — or point MDH at your own systems and watch them live: inbound webhooks, REST uptime checks, machine agents, and Node.js middleware all stream into one command center.
Five building blocks: an App (a workspace with its own keys and live stream), an Event (something that happened), an Endpoint (a URL subscribed to event patterns), a Delivery (one signed attempt, fully logged), and a Monitor (a live signal source — uptime poller, machine agent, or Node middleware).
https://mdhapi.com/api
Create an app in the dashboard first — every app gets its own keys, URLs, and live stream. Then three ways to get data flowing in under a minute:
curl -X POST https://mdhapi.com/api/ingest/APP_ID/events \
-H "Content-Type: application/json" \
-H "X-API-Key: mdk_live_..." \
-d '{"type":"payment.succeeded","data":{"amount":4200}}'curl -X POST https://mdhapi.com/api/hooks/YOUR_HOOK_SLUG \
-H "Content-Type: application/json" \
-d '{"type":"invoice.paid","amount":12900}'pip install psutil requests curl -o mdh_agent.py https://mdhapi.com/api/agent/script python mdh_agent.py --api https://mdhapi.com --key mdk_live_...
Everything you send lands in the app's live event stream in real time.
Three credential types, each built for a different caller. Every endpoint in the docs marks which ones it accepts: *(public)*, *(key)*, or *(session or PAT)*.
Personal access token (PAT) — for scripts, CI, and anything acting as *you* across the whole API (/apps, /auth/me, config, publishing). Create one in Settings → API; it is shown exactly once. Scopes: read (GET only), write (no deletes), admin (everything). A PAT can never create or revoke other tokens.
Authorization: Bearer mdh_pat_...
App API key — for event intake and agents, scoped to a single app. Created in the app's dashboard → Keys, starts with mdk_live_, shown once, rotated or revoked instantly. Scopes: read, publish, admin.
X-API-Key: mdk_live_... (event intake) X-Agent-Key: mdk_live_... (machine + node agents)
Session cookie — the browser dashboard only. Log in with email + password, Google, or GitHub; an httpOnly cookie rides every request. Scripts should always use a PAT instead — no login flow, no cookies.
wss://mdhapi.com/api/ws/apps/APP_ID?token=mdh_pat_... (browsers just use the session cookie)
Every Webhook Receiver app gets a public, unguessable intake URL. Point GitHub, Stripe, or any producer at it; MDH records each request and mirrors it into the live stream instantly.
X-GitHub-Event-style header or a type/event field in the payload. Store the producer's signing secret (e.g. a Stripe whsec_…) in the app config and forged requests are rejected with 400.Routing lives in the app config: set forward_url for a single pass-through destination, or forward_targets — a list of destinations, each with an optional transform template — to fan one inbound webhook out to several services in the exact shape each expects. The producer's original signature header is always passed through.
{
"url": "https://api.acme.dev/alerts",
"template": {
"text": "Order {{data.order_id}} paid {{data.amount}}",
"raw": "{{$raw}}"
}
}{{dot.path}} pulls values from the incoming JSON; {{$raw}} embeds the untouched body.
X-API-Key or Bearer, publish scope). Body: { type, data }. Returns the event id and mirrors it into the live stream instantly.limit up to 200). (session or PAT)payment.succeeded with a description. (session or PAT)Outbound delivery — MDH POSTs your events to customer URLs, signed and retried. Endpoints live under each app.
events matches everything; payment.* matches a namespace. The HMAC signing secret is returned once — store it. (session or PAT){ type, data } to every matching endpoint. (session or PAT — needs write scope)Live signal sources, all streaming into the same dashboard. Any of them can text you on failures — enable SMS in Settings → Profile.
REST API monitor — MDH pings your URL on your interval and charts uptime and latency. Down/recovered transitions alert you.
target_url, interval_s (min 10), and optional auth_header/auth_value. First ping lands within seconds. (session or PAT)Cron monitor — jobs ping a heartbeat URL when they finish; silence past the expected interval raises cron.missed. SSL monitor — server-side certificate checks with ssl.expiring alerts inside 14 days. Docker agent — container starts, stops, and health. Log watcher — tails any file, ships matching lines. SSH agent — login and command activity.
Machine agent — a dependency-light Python agent streams CPU, memory, disk, and processes from any Mac, Linux, or Windows host.
mdh_agent.py (machine). Also public: /agent/ssh-script, /agent/docker-script, /agent/log-script, /agent/listen-script.host_id. Auth: X-Agent-Key.{ host_id, system: {cpu, mem_pct, disk_pct}, children: [...] }. Auth: X-Agent-Key.The stream shows agent.connected, agent.disconnected (after 90s of silence), and resource.pressure events automatically.
Node.js middleware — drop mdh-monitor.mjs (from your app's dashboard) into any Express app. It reports per-route rpm, error rate, and p95 every 15 seconds — always, even with zero traffic, so the dashboard knows your app is alive.
{ routes: [{ method, route, rpm, err_pct, p95 }], heap_mb }. Auth: X-Agent-Key.The stream shows agent.connected on first report and route.discovered when a new endpoint appears.
Every delivery carries X-MDH-Signature: a timestamp and an HMAC-SHA256 of {t}.{raw body} using the endpoint secret. Always verify before processing, and reject timestamps older than 5 minutes.
const crypto = require("crypto");
function verifyMdh(rawBody, header, secret) {
const parts = Object.fromEntries(
header.split(",").map((kv) => kv.split("="))
);
const expected = crypto
.createHmac("sha256", secret)
.update(`${parts.t}.${rawBody}`)
.digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(parts.v1 || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Failed outbound deliveries retry with backoff — 1s, 5s, and 30s after the first attempt, four attempts total — before the delivery is marked failed. Every attempt is logged with status and latency in the deliveries list.
Inbound webhooks are never retried by MDH (the producer owns retries), but any received request can be replayed from the dashboard or the API, with optional re-forwarding to your routing target.
Every app has a realtime channel — the dashboard's live stream, monitor panels, and connection badges all ride it. Browsers authenticate with the session cookie automatically; scripts use a personal access token.
event, hook, uptime, metrics, agents, nodestats, and delivery messages as they happen, plus a ping heartbeat every 20 seconds. Auth: session cookie, Authorization: Bearer mdh_pat_… header, or ?token= query param.curl -o mdh_listen.mjs https://mdhapi.com/api/agent/listen-script MDH_TOKEN=mdh_pat_... node mdh_listen.mjs APP_ID
npx wscat -c "wss://mdhapi.com/api/ws/apps/APP_ID?token=mdh_pat_..."
No per-key request caps are enforced today. Plans carry a monthly event allowance (Developer: 10,000 events/month) and your current usage meter lives on the dashboard overview. Delivery retries and monitor intervals are tuned per app, so a slow endpoint never affects the rest of your traffic.
The agents and CLI are served live from the API — always the latest build. Specs and exports round out the toolchain.
Tip: every app can export its own always-current OpenAPI spec and Postman collection from its dashboard → API Reference.
Ask questions about this API or describe an integration and get generated SDK code. Pick your model per question.
How do
This is a looping preview. The real assistant answers from live docs, the changelog, and your own app's data.