Official JavaScript/TypeScript SDK for CallMeLater
npm install @callmelater/sdk
yarn add @callmelater/sdk
pnpm add @callmelater/sdk
import { CallMeLater } from "@callmelater/sdk";
// Initialize the client
const callMeLater = new CallMeLater({
apiKey: "your_api_key_here",
baseUrl: "https://api.callmelater.xyz", // optional, defaults to production
});
# .env
CALLMELATER_API_KEY=your_api_key_here
import { CallMeLater } from "@callmelater/sdk";
const callMeLater = new CallMeLater({
apiKey: process.env.CALLMELATER_API_KEY,
});
// Schedule a simple POST request
const result = await callMeLater.schedule({
targetUrl: "https://api.example.com/webhook",
targetMethod: "POST",
targetHeaders: {
"Content-Type": "application/json",
Authorization: "Bearer your-token",
},
targetBody: {
message: "Hello from the future!",
timestamp: new Date().toISOString(),
},
triggerAt: new Date(Date.now() + 3600000), // 1 hour from now
});
console.log("Scheduled:", result.scheduleId);
import {
CallMeLater,
ScheduleRequest,
ScheduleResponse,
} from "@callmelater/sdk";
const callMeLater = new CallMeLater({
apiKey: process.env.CALLMELATER_API_KEY!,
});
const scheduleData: ScheduleRequest = {
targetUrl: "https://api.example.com/webhook",
targetMethod: "POST",
targetHeaders: {
"Content-Type": "application/json",
},
targetBody: {
userId: "12345",
action: "reminder",
},
triggerAt: new Date(Date.now() + 86400000), // 24 hours from now
};
const response: ScheduleResponse = await callMeLater.schedule(scheduleData);
// Schedule for a specific time
const tomorrow9AM = await callMeLater.scheduleAt(
new Date("2024-03-20T09:00:00Z"),
{
targetUrl: "https://api.example.com/daily-report",
targetMethod: "POST",
}
);
// Schedule with a delay
const in30Minutes = await callMeLater.scheduleIn(
30 * 60 * 1000, // 30 minutes in milliseconds
{
targetUrl: "https://api.example.com/reminder",
targetMethod: "POST",
targetBody: { message: "Meeting in 30 minutes!" },
}
);
// Schedule for tomorrow at a specific time
const tomorrowReminder = await callMeLater.scheduleTomorrow(
{ hour: 9, minute: 0 }, // 9:00 AM
{
targetUrl: "https://api.example.com/morning-reminder",
targetMethod: "POST",
}
);
// Cancel using schedule ID
await callMeLater.cancel("sch_abc123");
// Cancel with error handling
try {
await callMeLater.cancel("sch_abc123");
console.log("Schedule cancelled successfully");
} catch (error) {
if (error.status === 404) {
console.log("Schedule not found or already executed");
} else {
console.error("Failed to cancel:", error.message);
}
}
// Schedule multiple requests
const requests = [
{
targetUrl: "https://api.example.com/user/1/reminder",
targetMethod: "POST",
triggerAt: new Date("2024-03-20T09:00:00Z"),
},
{
targetUrl: "https://api.example.com/user/2/reminder",
targetMethod: "POST",
triggerAt: new Date("2024-03-20T09:00:00Z"),
},
];
const results = await callMeLater.scheduleMany(requests);
console.log(
`Scheduled ${results.successful.length} of ${requests.length} requests`
);
// Cancel multiple schedules
const scheduleIds = ["sch_123", "sch_456", "sch_789"];
const cancelResults = await callMeLater.cancelMany(scheduleIds);
// Check remaining credits
const credits = await callMeLater.getCredits();
console.log(`Credits remaining: ${credits}`);
// Get usage statistics
const stats = await callMeLater.getStats({
from: new Date("2024-03-01"),
to: new Date("2024-03-31"),
});
console.log(
`Success rate: ${(
(stats.successfulInvocations / stats.totalInvocations) *
100
).toFixed(1)}%`
);
// Get recent logs
const logs = await callMeLater.getLogs({
limit: 50,
order: "desc",
});
// Filter logs by status
const failedLogs = await callMeLater.getLogs({
status: "failed",
limit: 100,
});
// Filter by date range
const lastWeekLogs = await callMeLater.getLogs({
from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
to: new Date(),
});
// Filter by target URL
const webhookLogs = await callMeLater.getLogs({
targetUrl: "https://api.example.com/webhook",
});
import { CallMeLaterError } from "@callmelater/sdk";
try {
const result = await callMeLater.schedule({
targetUrl: "https://api.example.com/webhook",
targetMethod: "POST",
triggerAt: new Date(Date.now() + 3600000),
});
console.log("Success:", result.scheduleId);
} catch (error) {
if (error instanceof CallMeLaterError) {
switch (error.status) {
case 401:
console.error("Invalid API key");
break;
case 402:
console.error("Insufficient credits");
break;
case 400:
console.error("Invalid request:", error.details);
break;
default:
console.error("API error:", error.message);
}
} else {
console.error("Network error:", error.message);
}
}
const scheduleWithRetry = async (requestData, maxRetries = 3) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await callMeLater.schedule(requestData);
} catch (error) {
if (
attempt === maxRetries ||
error.status === 401 ||
error.status === 402
) {
throw error; // Don't retry auth or credit errors
}
const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
};
// Configure timeout and retry behavior
const callMeLater = new CallMeLater({
apiKey: process.env.CALLMELATER_API_KEY,
timeout: 10000, // 10 seconds
retries: 3,
retryDelay: 1000, // 1 second between retries
});
// Use custom headers for all requests
const callMeLater = new CallMeLater({
apiKey: process.env.CALLMELATER_API_KEY,
defaultHeaders: {
"X-Client-Version": "1.0.0",
"User-Agent": "MyApp/1.0",
},
});
// Helper for scheduling webhook chains
class WebhookChain {
constructor(callMeLater) {
this.client = callMeLater;
this.steps = [];
}
addStep(delay, requestData) {
this.steps.push({ delay, requestData });
return this;
}
async execute(startTime = new Date()) {
const results = [];
let currentTime = new Date(startTime);
for (const step of this.steps) {
currentTime = new Date(currentTime.getTime() + step.delay);
const result = await this.client.schedule({
...step.requestData,
triggerAt: currentTime,
});
results.push(result);
}
return results;
}
}
// Usage
const chain = new WebhookChain(callMeLater)
.addStep(0, {
// Immediate
targetUrl: "https://api.example.com/start",
targetMethod: "POST",
})
.addStep(300000, {
// 5 minutes later
targetUrl: "https://api.example.com/check",
targetMethod: "GET",
})
.addStep(600000, {
// 10 minutes after start
targetUrl: "https://api.example.com/cleanup",
targetMethod: "DELETE",
});
const results = await chain.execute();
// In a browser environment
import { CallMeLater } from "@callmelater/sdk";
const callMeLater = new CallMeLater({
apiKey: "your_public_api_key", // Use a restricted key for browser usage
});
// Schedule from browser
document.getElementById("scheduleBtn").addEventListener("click", async () => {
try {
const result = await callMeLater.schedule({
targetUrl: "https://api.example.com/webhook",
targetMethod: "POST",
targetBody: {
source: "browser",
timestamp: new Date().toISOString(),
},
triggerAt: new Date(Date.now() + 60000), // 1 minute from now
});
console.log("Scheduled from browser:", result.scheduleId);
} catch (error) {
console.error("Failed to schedule:", error.message);
}
});
Option | Type | Default | Description |
---|---|---|---|
apiKey | string | Required | Your CallMeLater API key |
baseUrl | string | https://api.callmelater.xyz | API base URL |
timeout | number | 30000 | Request timeout in milliseconds |
retries | number | 3 | Number of retry attempts |
retryDelay | number | 1000 | Delay between retries in milliseconds |
defaultHeaders | object | {} | Default headers for all requests |
interface ScheduleRequest {
targetUrl: string;
targetMethod: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD";
targetHeaders?: Record<string, string>;
targetBody?: any;
triggerAt: Date | string;
}
interface ScheduleResponse {
scheduleId: string;
invocationId: string;
message: string;
}
interface LogEntry {
invocationId: string;
scheduleId: string;
createdAt: string;
scheduledAt: string;
targetUrl: string;
targetMethod: string;
status: "scheduled" | "completed" | "failed" | "cancelled";
statusCode: number;
responseTimeMs: number;
errorMessage: string;
}
interface UsageStats {
totalInvocations: number;
successfulInvocations: number;
failedInvocations: number;
averageResponseTime: number;
timeRange: {
from: string;
to: string;
};
}