Skip to content

JavaScript and TypeScript

The Stormedo JavaScript SDK supports Node.js 22 and newer. Create one client with a project API key and reuse it throughout your server application.

npm install @stormedo/sdk
import { Stormedo } from "@stormedo/sdk";
const stormedo = new Stormedo(process.env.STORMEDO_TOKEN!);

Keep STORMEDO_TOKEN in server-side configuration. Do not expose a project API key to browser code.

const request = await stormedo.send("https://your-app.example/webhooks/stormedo", {
body: {
type: "order.created",
orderId: "ord_123",
},
delay: { minutes: 5 },
maxAttempts: 5,
});
console.log(request.id, request.status);

maxAttempts counts the initial attempt.

Use rawBody when Stormedo must forward bytes unchanged.

await stormedo.send("https://your-app.example/events", {
rawBody: new TextEncoder().encode("event=created"),
contentType: "application/x-www-form-urlencoded",
headers: {
Authorization: "Bearer destination-token",
},
});

The headers you provide are sent to the destination. Stormedo never forwards your project API key.

Submit multiple independent requests in one API call:

const requests = await stormedo.sendBatch([
{
url: "https://your-app.example/webhooks/orders",
body: { type: "order.created", orderId: "ord_123" },
},
{
url: "https://your-app.example/webhooks/inventory",
body: { type: "inventory.sync", warehouseId: "wh_7" },
delay: { hours: 1 },
},
]);
console.log(requests.map((request) => request.id));

delay and timeout accept duration objects with days, hours, minutes, and seconds. deliverAt accepts a Date.

listRequests supports status, search, method, source, time range, cursor, and limit filters:

const page = await stormedo.listRequests({
status: "failed",
method: "POST",
limit: 25,
});
console.log(page.items);
if (page.nextCursor) {
const nextPage = await stormedo.listRequests({
status: "failed",
method: "POST",
limit: 25,
cursor: page.nextCursor,
});
console.log(nextPage.items);
}

Load request detail and completed attempts independently:

const detail = await stormedo.getRequest(request.id);
const attempts = await stormedo.listRequestAttempts(request.id);
console.log(detail.status, attempts.length);
await stormedo.cancelRequest(request.id);
const replay = await stormedo.replayRequest(request.id);
console.log(replay.id);

Cancellation preserves the original request and attempt history. Replay creates a new request linked to the original.

Create schedules with cron or fixed-interval timing:

import { cronTiming, intervalTiming } from "@stormedo/sdk";
const schedule = await stormedo.createSchedule({
name: "sync-inventory",
timing: cronTiming("0 */6 * * *", "Asia/Kolkata"),
url: "https://your-app.example/inventory/sync",
body: { fullSync: true },
maxAttempts: 4,
});
await stormedo.updateSchedule(schedule.id, {
timing: intervalTiming({ hours: 4 }),
});
const schedules = await stormedo.listSchedules();
const definition = await stormedo.getSchedule(schedule.id);
console.log(schedules.length, definition.status);
await stormedo.pauseSchedule(schedule.id);
await stormedo.resumeSchedule(schedule.id);
await stormedo.deleteSchedule(schedule.id);

cronTiming accepts a five-field cron expression and an IANA timezone. intervalTiming accepts days, hours, and minutes; the combined duration must be a whole number of minutes from one minute through 30 days. Pass a future Date as startsAt to choose the first run time.

API and network failures throw StormedoError. Use code for program logic and requestId when contacting Stormedo support.

import { StormedoError } from "@stormedo/sdk";
try {
await stormedo.getRequest("req_33uZSQsVaf8aZjDuzkuAq");
} catch (error) {
if (error instanceof StormedoError) {
console.error(error.code, error.status, error.requestId, error.details);
}
}

Read Delivery verification before processing signed requests at your destination.