JavaScript SDK

The CallMeLater JavaScript SDK provides a convenient way to interact with the CallMeLater API from Node.js applications and browsers. It includes TypeScript definitions and handles authentication, request formatting, and error handling automatically.

Installation

Install the SDK using npm or yarn:
npm install @callmelater/sdk
yarn add @callmelater/sdk
pnpm add @callmelater/sdk

Quick Start

Basic Setup

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
});

Environment Variables

For production applications, use environment variables:
# .env
CALLMELATER_API_KEY=your_api_key_here
import { CallMeLater } from "@callmelater/sdk";

const callMeLater = new CallMeLater({
  apiKey: process.env.CALLMELATER_API_KEY,
});

Scheduling Requests

Basic Scheduling

// 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);

TypeScript Support

The SDK includes full TypeScript definitions:
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);

Convenience Methods

The SDK provides convenience methods for common scheduling patterns:
// 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",
  }
);

Managing Schedules

Cancel Scheduled Requests

// 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);
  }
}

Bulk Operations

// 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);

Monitoring and Analytics

Get Account Information

// 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)}%`
);

Retrieve Logs

// 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",
});

Error Handling

Comprehensive Error Handling

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);
  }
}

Retry Logic

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));
    }
  }
};

Advanced Usage

Custom Request Configuration

// 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",
  },
});

Webhook Helpers

// 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();

Browser Usage

The SDK also works in browsers (with appropriate CORS configuration):
// 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);
  }
});

Configuration Options

OptionTypeDefaultDescription
apiKeystringRequiredYour CallMeLater API key
baseUrlstringhttps://api.callmelater.xyzAPI base URL
timeoutnumber30000Request timeout in milliseconds
retriesnumber3Number of retry attempts
retryDelaynumber1000Delay between retries in milliseconds
defaultHeadersobject{}Default headers for all requests

TypeScript Definitions

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;
  };
}