Webhook ingestion
Forward a webhook from any upstream into MemHQ as episodes.
Webhook ingestion
For sources that don't have a managed connector, the pattern is: stand
up a thin handler that receives the upstream webhook and translates it
into one /v1/memhq/add call per event.
Example: Slack message webhook
// app/api/slack/route.ts (Next.js)
import { NextResponse } from "next/server";
import { MemoryClient } from "@memhq/sdk";
const memhq = new MemoryClient();
export async function POST(req: Request) {
const body = await req.json();
// Slack URL verification — respond once on first setup.
if (body.type === "url_verification") {
return NextResponse.json({ challenge: body.challenge });
}
const event = body.event;
if (event?.type !== "message" || event.subtype) {
return NextResponse.json({ ok: true });
}
// Map Slack user → MemHQ user. In practice you'd look up the linked
// identity in your own DB; for the example we use the Slack user ID
// directly.
await memhq.add({
userId: `slack:${event.user}`,
groupId: `slack:channel:${event.channel}`,
messages: [
{
role: "user",
content: event.text,
},
],
metadata: {
source: "slack",
ts: event.ts,
channel: event.channel,
},
});
return NextResponse.json({ ok: true });
}Slack delivers the same event multiple times under retries. The
reconciler's reinforce path absorbs the duplicates, but you can also
short-circuit by hashing event.ts and skipping replays.
Bulk import from a file
For one-time backfill from an export (a JSON dump, a CSV of past
transcripts), batch the add calls with bounded concurrency:
import { MemoryClient } from "@memhq/sdk";
import pLimit from "p-limit";
const memhq = new MemoryClient();
const limit = pLimit(8);
const transcripts: Transcript[] = JSON.parse(await Bun.file("export.json").text());
await Promise.all(
transcripts.map((t) =>
limit(() =>
memhq.add({
userId: t.userId,
messages: t.messages,
metadata: { source: "backfill", original_id: t.id },
}),
),
),
);The ingestion worker processes the queue at its own pace; the API accepts 4-figure-per-second peak bursts without backpressure.
Coming soon — full guide
Worked examples for Linear, GitHub, and Notion webhooks are in progress.