Getting Started | Locci Scheduler

Locci Scheduler is a webhook scheduling platform that allows you to schedule HTTP requests to be executed at specific times or intervals.

1. Create an Account

curl -X POST https://api.scheduler.locci.cloud/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email": "your-email@example.com", "password": "your-secure-password"}'

2. Login

curl -X POST https://api.scheduler.locci.cloud/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "your-email@example.com", "password": "your-secure-password"}'

Save the access_token from the response.

3. Generate an API Key

curl -X POST https://api.scheduler.locci.cloud/api/v1/auth/key \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -d '{"expiry_time_days": 60}'

Save the api_key securely - this is what you'll use in your applications.

4. Install an SDK

JavaScript/TypeScript:

npm install @locci/scheduler

Rust:

Add with Cargo toolchain

cargo add locci-scheduler

Or add the crate in Cargo.toml file

[dependencies]
locci-scheduler = "0.1.0"
tokio = { version = "1", features = ["full"] }

5. Configure Environment

# .env
LOCCI_SCHEDULER_URL=https://api.scheduler.locci.cloud
LOCCI_SCHEDULER_TOKEN=your-api-key-here

Next Steps

For detailed SDK usage, examples, and API reference:

Support

JavaScript/TypeScript SDK

The official JavaScript/TypeScript SDK for Locci Scheduler provides a type-safe, promise-based API for scheduling webhook tasks.

Installation

npm install @locci/scheduler

Or with other package managers:

bun add @locci/scheduler
pnpm add @locci/scheduler
yarn add @locci/scheduler

Quick Start

import { LocciScheduler } from "@locci/scheduler";

const scheduler = new LocciScheduler({
  baseUrl: "https://api.scheduler.locci.cloud",
  apiToken: "your-api-key",
});

// Create a one-time task
const task = await scheduler.scheduleOnce({
  name: "My First Task",
  webhook: {
    url: "https://your-app.com/webhook",
    method: "POST",
    payload: { message: "Hello!" },
  },
  executeAt: new Date(Date.now() + 5 * 60 * 1000), // 5 minutes from now
});

console.log("Task created:", task.id);

Configuration

import { LocciScheduler } from "@locci/scheduler";

const scheduler = new LocciScheduler({
  baseUrl: "https://api.scheduler.locci.cloud", // API base URL
  apiToken: "your-api-key",                     // Your API key from the console
  timeout: 30000,                               // Request timeout in ms (default: 30000)
  retries: 3,                                   // Number of retries (default: 3)
});

Environment Variables

For production, use environment variables:

import dotenv from "dotenv";
dotenv.config();

const scheduler = new LocciScheduler({
  baseUrl: process.env.LOCCI_SCHEDULER_URL,
  apiToken: process.env.LOCCI_SCHEDULER_TOKEN,
});

Task Management

Create a Task

const task = await scheduler.createTask({
  name: "Daily Report",
  description: "Send daily sales report",
  webhook: {
    url: "https://your-app.com/api/reports",
    method: "POST",
    headers: {
      "X-Custom-Header": "value",
    },
    payload: {
      reportType: "sales",
      period: "daily",
    },
    timeoutSeconds: 30,
  },
  schedule: {
    type: "recurring",
    cronExpression: "0 9 * * *", // Every day at 9 AM
    timezone: "Africa/Nairobi",
  },
  metadata: {
    department: "sales",
    priority: "high",
  },
});

Get a Task

const task = await scheduler.getTask("task-id-here");
console.log(task.name, task.status);

List Tasks

const taskList = await scheduler.listTasks({
  page: 1,
  perPage: 10,
});

console.log(`Total tasks: ${taskList.total}`);
taskList.tasks.forEach((task) => {
  console.log(`- ${task.name} (${task.status})`);
});

Update a Task

const updatedTask = await scheduler.updateTask("task-id", {
  name: "Updated Task Name",
  description: "New description",
});

Delete a Task

await scheduler.deleteTask("task-id");

Task Lifecycle

Pause a Task

const task = await scheduler.pauseTask("task-id");
console.log(task.status); // "Paused"

Resume a Task

const task = await scheduler.resumeTask("task-id");
console.log(task.status); // "Active"

Cancel a Task

const task = await scheduler.cancelTask("task-id");
console.log(task.status); // "Cancelled"

Manually Trigger a Task

await scheduler.triggerTask("task-id");

Scheduling Methods

One-Time Execution

const task = await scheduler.scheduleOnce({
  name: "Send Welcome Email",
  webhook: {
    url: "https://your-app.com/api/emails/welcome",
    method: "POST",
    payload: { userId: "user123" },
  },
  executeAt: new Date("2024-12-25T09:00:00Z"),
  description: "Send welcome email to new user",
  metadata: { userId: "user123" },
});

Recurring with Cron Expression

const task = await scheduler.scheduleRecurring({
  name: "Weekly Backup",
  webhook: {
    url: "https://your-app.com/api/backup",
    method: "POST",
  },
  cronExpression: "0 2 * * 0", // Sundays at 2 AM
  timezone: "UTC",
  endDate: new Date("2025-12-31"), // Optional end date
});

Interval-Based

const task = await scheduler.scheduleInterval({
  name: "Health Check",
  webhook: {
    url: "https://your-app.com/health",
    method: "GET",
    timeoutSeconds: 10,
  },
  intervalSeconds: 300, // Every 5 minutes
  startAt: new Date(),  // Start immediately
});

Daily at Specific Time

const task = await scheduler.scheduleDaily({
  name: "Daily Sales Report",
  webhook: {
    url: "https://your-app.com/api/reports/daily",
    method: "POST",
  },
  time: "09:00", // 9:00 AM (24-hour format)
  timezone: "Africa/Nairobi",
});

Weekly

const task = await scheduler.scheduleWeekly({
  name: "Weekly Team Standup Reminder",
  webhook: {
    url: "https://your-app.com/api/slack/notify",
    method: "POST",
    payload: { message: "Team standup in 15 minutes!" },
  },
  dayOfWeek: 1, // Monday (0 = Sunday)
  time: "09:45",
  timezone: "Africa/Nairobi",
});

Convenience Methods

// Every minute
await scheduler.scheduleEveryMinute({
  name: "Minute Task",
  webhook: { url: "https://example.com/ping", method: "GET" },
});

// Every hour
await scheduler.scheduleEveryHour({
  name: "Hourly Task",
  webhook: { url: "https://example.com/hourly", method: "POST" },
});

Webhook Configuration

Basic Webhook

const webhook = {
  url: "https://your-app.com/webhook",
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Custom-Header": "value",
  },
  payload: {
    key: "value",
  },
  timeoutSeconds: 30,
};

With Retry Configuration

const webhook = {
  url: "https://your-app.com/webhook",
  method: "POST",
  retryConfig: {
    maxAttempts: 5,
    backoffSeconds: 2,
    backoffMultiplier: 2.0,
    maxBackoffSeconds: 300,
  },
};

Authentication Types

API Key

const webhook = {
  url: "https://your-app.com/webhook",
  method: "POST",
  authentication: {
    type: "apiKey",
    apiKey: {
      headerName: "X-API-Key",
      key: "your-api-key-value",
    },
  },
};

Bearer Token

const webhook = {
  url: "https://your-app.com/webhook",
  method: "POST",
  authentication: {
    type: "bearerToken",
    bearerToken: {
      token: "your-bearer-token",
    },
  },
};

Basic Auth

const webhook = {
  url: "https://your-app.com/webhook",
  method: "POST",
  authentication: {
    type: "basicAuth",
    basicAuth: {
      username: "user",
      password: "password",
    },
  },
};

HMAC Webhook Signature

For secure webhook verification, use webhookSecret:

const webhook = {
  url: "https://your-app.com/webhook",
  method: "POST",
  payload: { data: "sensitive" },
  webhookSecret: "your-webhook-secret",
};

The scheduler will include an X-Locci-Signature header with an HMAC-SHA256 signature of the payload. Verify it on your server:

import crypto from "crypto";

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac("sha256", secret)
    .update(JSON.stringify(payload))
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

Execution History

const history = await scheduler.getTaskHistory("task-id");

console.log(`Total executions: ${history.total}`);
history.executions.forEach((exec) => {
  console.log(`- ${exec.executedAt}: ${exec.status}`);
  if (exec.errorMessage) {
    console.log(`  Error: ${exec.errorMessage}`);
  }
});

Error Handling

The SDK provides specific error classes for different scenarios:

import {
  SchedulerError,
  AuthenticationError,
  ValidationError,
  NotFoundError,
  RateLimitError,
} from "@locci/scheduler";

try {
  const task = await scheduler.createTask({
    // ... task configuration
  });
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error("Authentication failed - check your API key");
  } else if (error instanceof ValidationError) {
    console.error("Invalid task configuration:", error.details);
  } else if (error instanceof NotFoundError) {
    console.error("Resource not found");
  } else if (error instanceof RateLimitError) {
    console.error("Rate limit exceeded - please wait and retry");
  } else if (error instanceof SchedulerError) {
    console.error(`API error (${error.statusCode}):`, error.message);
  } else {
    console.error("Unexpected error:", error);
  }
}

TypeScript Types

All types are exported from the package:

import type {
  Task,
  TaskExecution,
  TaskStatus,
  ExecutionStatus,
  SchedulerConfig,
  CreateTaskOptions,
  UpdateTaskOptions,
  WebhookConfig,
  ScheduleConfig,
  AuthConfig,
  RetryConfig,
  HttpMethod,
  PaginationOptions,
  TaskListResponse,
  TaskHistoryResponse,
} from "@locci/scheduler";

Type Definitions

// Task status values
type TaskStatus = "Active" | "Paused" | "Completed" | "Failed" | "Cancelled";

// Execution status values
type ExecutionStatus = "Success" | "Failed" | "Retrying" | "TimedOut";

// HTTP methods
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";

// Schedule types
type ScheduleType = "once" | "recurring" | "interval";

Common Use Cases

User Onboarding Email Sequence

async function scheduleOnboardingEmails(userId: string, email: string) {
  const baseTime = new Date();

  // Welcome email - 2 minutes after signup
  await scheduler.scheduleOnce({
    name: `Welcome Email - ${userId}`,
    webhook: {
      url: "https://your-app.com/api/emails/send",
      method: "POST",
      payload: { to: email, template: "welcome", userId },
    },
    executeAt: new Date(baseTime.getTime() + 2 * 60 * 1000),
    metadata: { userId, emailType: "welcome" },
  });

  // Tips email - 1 day after signup
  await scheduler.scheduleOnce({
    name: `Tips Email - ${userId}`,
    webhook: {
      url: "https://your-app.com/api/emails/send",
      method: "POST",
      payload: { to: email, template: "tips", userId },
    },
    executeAt: new Date(baseTime.getTime() + 24 * 60 * 60 * 1000),
    metadata: { userId, emailType: "tips" },
  });

  // Follow-up email - 3 days after signup
  await scheduler.scheduleOnce({
    name: `Follow-up Email - ${userId}`,
    webhook: {
      url: "https://your-app.com/api/emails/send",
      method: "POST",
      payload: { to: email, template: "followup", userId },
    },
    executeAt: new Date(baseTime.getTime() + 3 * 24 * 60 * 60 * 1000),
    metadata: { userId, emailType: "followup" },
  });
}

Health Monitoring

async function setupHealthMonitoring(services: string[]) {
  for (const service of services) {
    await scheduler.scheduleInterval({
      name: `Health Check - ${service}`,
      webhook: {
        url: `https://${service}.your-domain.com/health`,
        method: "GET",
        timeoutSeconds: 10,
      },
      intervalSeconds: 60, // Check every minute
      metadata: { service, type: "health-check" },
    });
  }
}

Subscription Renewal Reminders

async function scheduleRenewalReminder(
  userId: string,
  email: string,
  renewalDate: Date
) {
  // Reminder 7 days before
  const reminderDate = new Date(renewalDate.getTime() - 7 * 24 * 60 * 60 * 1000);

  await scheduler.scheduleOnce({
    name: `Renewal Reminder - ${userId}`,
    webhook: {
      url: "https://your-app.com/api/emails/send",
      method: "POST",
      payload: {
        to: email,
        template: "renewal_reminder",
        userId,
        renewalDate: renewalDate.toISOString(),
      },
    },
    executeAt: reminderDate,
    metadata: { userId, type: "renewal_reminder" },
  });
}

Resources

Rust SDK

The official Rust SDK for Locci Scheduler provides a type-safe, async API for scheduling webhook tasks using the Tokio runtime.

Installation

Add to your Cargo.toml:

[dependencies]
locci-scheduler = "0.1.0"
tokio = { version = "1", features = ["full"] }
chrono = "0.4"
serde_json = "1.0"

Or add with Cargo toolchain

cargo add locci-scheduler

Quick Start

use locci_scheduler::{LocciScheduler, SchedulerConfig, WebhookConfig, HttpMethod};
use chrono::Utc;

#[tokio::main]
async fn main() -> locci_scheduler::Result<()> {
    let config = SchedulerConfig {
        base_url: "https://api.scheduler.locci.cloud".to_string(),
        api_token: "your-api-key".to_string(),
        timeout: 30000,
        retries: 3,
    };

    let scheduler = LocciScheduler::new(config)?;

    // Create a one-time task
    let webhook = WebhookConfig {
        url: "https://your-app.com/webhook".to_string(),
        method: Some(HttpMethod::Post),
        headers: None,
        payload: Some(serde_json::json!({ "message": "Hello!" })),
        timeout_seconds: Some(30),
        retry_config: None,
        authentication: None,
        webhook_secret: None,
    };

    let execute_at = Utc::now() + chrono::Duration::minutes(5);
    let task = scheduler.schedule_once(
        "My First Task".to_string(),
        webhook,
        execute_at,
        Some("A test task".to_string()),
        None,
    ).await?;

    println!("Task created: {}", task.id);
    Ok(())
}

Configuration

#![allow(unused)]
fn main() {
use locci_scheduler::SchedulerConfig;

let config = SchedulerConfig {
    base_url: "https://api.scheduler.locci.cloud".to_string(),
    api_token: "your-api-key".to_string(),
    timeout: 30000,  // Request timeout in milliseconds
    retries: 3,      // Number of retry attempts
};

let scheduler = LocciScheduler::new(config)?;
}

Environment Variables

For production, use environment variables:

#![allow(unused)]
fn main() {
use std::env;

let config = SchedulerConfig {
    base_url: env::var("LOCCI_SCHEDULER_URL")
        .unwrap_or_else(|_| "https://api.scheduler.locci.cloud".to_string()),
    api_token: env::var("LOCCI_SCHEDULER_TOKEN")
        .expect("LOCCI_SCHEDULER_TOKEN must be set"),
    timeout: 30000,
    retries: 3,
};
}

Task Management

Create a Task

#![allow(unused)]
fn main() {
use locci_scheduler::{CreateTaskOptions, WebhookConfig, ScheduleConfig, HttpMethod};
use chrono::Utc;
use std::collections::HashMap;

let webhook = WebhookConfig {
    url: "https://your-app.com/api/reports".to_string(),
    method: Some(HttpMethod::Post),
    headers: Some({
        let mut h = HashMap::new();
        h.insert("X-Custom-Header".to_string(), "value".to_string());
        h
    }),
    payload: Some(serde_json::json!({
        "reportType": "sales",
        "period": "daily"
    })),
    timeout_seconds: Some(30),
    retry_config: None,
    authentication: None,
    webhook_secret: None,
};

let task = scheduler.create_task(CreateTaskOptions {
    name: "Daily Report".to_string(),
    description: Some("Send daily sales report".to_string()),
    webhook,
    schedule: ScheduleConfig::Recurring {
        cron_expression: "0 9 * * *".to_string(),
        timezone: Some("Africa/Nairobi".to_string()),
        end_date: None,
    },
    metadata: Some({
        let mut m = HashMap::new();
        m.insert("department".to_string(), serde_json::json!("sales"));
        m
    }),
}).await?;
}

Get a Task

#![allow(unused)]
fn main() {
let task = scheduler.get_task("task-id-here").await?;
println!("Task: {} - Status: {:?}", task.name, task.status);
}

List Tasks

#![allow(unused)]
fn main() {
use locci_scheduler::PaginationOptions;

let task_list = scheduler.list_tasks(PaginationOptions {
    page: Some(1),
    per_page: Some(10),
}).await?;

println!("Total tasks: {}", task_list.total);
for task in &task_list.tasks {
    println!("- {} ({:?})", task.name, task.status);
}
}

Update a Task

#![allow(unused)]
fn main() {
use locci_scheduler::UpdateTaskOptions;

let updated_task = scheduler.update_task("task-id", UpdateTaskOptions {
    name: Some("Updated Task Name".to_string()),
    description: Some("New description".to_string()),
    ..Default::default()
}).await?;
}

Delete a Task

#![allow(unused)]
fn main() {
scheduler.delete_task("task-id").await?;
}

Task Lifecycle

Pause a Task

#![allow(unused)]
fn main() {
let task = scheduler.pause_task("task-id").await?;
println!("Task status: {:?}", task.status); // Paused
}

Resume a Task

#![allow(unused)]
fn main() {
let task = scheduler.resume_task("task-id").await?;
println!("Task status: {:?}", task.status); // Active
}

Cancel a Task

#![allow(unused)]
fn main() {
let task = scheduler.cancel_task("task-id").await?;
println!("Task status: {:?}", task.status); // Cancelled
}

Manually Trigger a Task

#![allow(unused)]
fn main() {
scheduler.trigger_task("task-id").await?;
}

Scheduling Methods

One-Time Execution

#![allow(unused)]
fn main() {
use chrono::{Utc, TimeZone};

let webhook = WebhookConfig {
    url: "https://your-app.com/api/emails/welcome".to_string(),
    method: Some(HttpMethod::Post),
    headers: None,
    payload: Some(serde_json::json!({ "userId": "user123" })),
    timeout_seconds: Some(30),
    retry_config: None,
    authentication: None,
    webhook_secret: None,
};

let execute_at = Utc.with_ymd_and_hms(2024, 12, 25, 9, 0, 0).unwrap();

let task = scheduler.schedule_once(
    "Send Welcome Email".to_string(),
    webhook,
    execute_at,
    Some("Send welcome email to new user".to_string()),
    Some({
        let mut m = HashMap::new();
        m.insert("userId".to_string(), serde_json::json!("user123"));
        m
    }),
).await?;
}

Recurring with Cron Expression

#![allow(unused)]
fn main() {
let task = scheduler.schedule_recurring(
    "Weekly Backup".to_string(),
    webhook,
    "0 2 * * 0".to_string(), // Sundays at 2 AM
    Some("UTC".to_string()),
    Some(Utc.with_ymd_and_hms(2025, 12, 31, 23, 59, 59).unwrap()), // End date
    Some("Weekly database backup".to_string()),
    None,
).await?;
}

Interval-Based

#![allow(unused)]
fn main() {
let task = scheduler.schedule_interval(
    "Health Check".to_string(),
    webhook,
    300, // Every 5 minutes (300 seconds)
    Some(Utc::now()), // Start immediately
    None, // No end date
    Some("Monitor API health".to_string()),
    None,
).await?;
}

Daily at Specific Time

#![allow(unused)]
fn main() {
let task = scheduler.schedule_daily(
    "Daily Sales Report".to_string(),
    webhook,
    "09:00", // 9:00 AM (24-hour format)
    Some("Africa/Nairobi".to_string()),
    Some("Generate and send daily sales report".to_string()),
    None,
).await?;
}

Weekly

#![allow(unused)]
fn main() {
let task = scheduler.schedule_weekly(
    "Weekly Team Standup Reminder".to_string(),
    webhook,
    1, // Monday (0 = Sunday, 1 = Monday, etc.)
    "09:45",
    Some("Africa/Nairobi".to_string()),
    Some("Remind team about standup".to_string()),
    None,
).await?;
}

Convenience Methods

#![allow(unused)]
fn main() {
// Every minute
let task = scheduler.schedule_every_minute(
    "Minute Task".to_string(),
    webhook.clone(),
    None,
    None,
).await?;

// Every hour
let task = scheduler.schedule_every_hour(
    "Hourly Task".to_string(),
    webhook,
    None,
    None,
).await?;
}

Webhook Configuration

Basic Webhook

#![allow(unused)]
fn main() {
use std::collections::HashMap;

let webhook = WebhookConfig {
    url: "https://your-app.com/webhook".to_string(),
    method: Some(HttpMethod::Post),
    headers: Some({
        let mut h = HashMap::new();
        h.insert("Content-Type".to_string(), "application/json".to_string());
        h.insert("X-Custom-Header".to_string(), "value".to_string());
        h
    }),
    payload: Some(serde_json::json!({ "key": "value" })),
    timeout_seconds: Some(30),
    retry_config: None,
    authentication: None,
    webhook_secret: None,
};
}

With Retry Configuration

#![allow(unused)]
fn main() {
use locci_scheduler::RetryConfig;

let webhook = WebhookConfig {
    url: "https://your-app.com/webhook".to_string(),
    method: Some(HttpMethod::Post),
    headers: None,
    payload: None,
    timeout_seconds: Some(30),
    retry_config: Some(RetryConfig {
        max_attempts: 5,
        backoff_seconds: 2,
        backoff_multiplier: 2.0,
        max_backoff_seconds: 300,
    }),
    authentication: None,
    webhook_secret: None,
};
}

Authentication Types

API Key

#![allow(unused)]
fn main() {
use locci_scheduler::AuthConfig;

let webhook = WebhookConfig {
    url: "https://your-app.com/webhook".to_string(),
    method: Some(HttpMethod::Post),
    headers: None,
    payload: None,
    timeout_seconds: Some(30),
    retry_config: None,
    authentication: Some(AuthConfig::ApiKey {
        header_name: "X-API-Key".to_string(),
        key: "your-api-key-value".to_string(),
    }),
    webhook_secret: None,
};
}

Bearer Token

#![allow(unused)]
fn main() {
let webhook = WebhookConfig {
    url: "https://your-app.com/webhook".to_string(),
    method: Some(HttpMethod::Post),
    headers: None,
    payload: None,
    timeout_seconds: Some(30),
    retry_config: None,
    authentication: Some(AuthConfig::BearerToken {
        token: "your-bearer-token".to_string(),
    }),
    webhook_secret: None,
};
}

Basic Auth

#![allow(unused)]
fn main() {
let webhook = WebhookConfig {
    url: "https://your-app.com/webhook".to_string(),
    method: Some(HttpMethod::Post),
    headers: None,
    payload: None,
    timeout_seconds: Some(30),
    retry_config: None,
    authentication: Some(AuthConfig::BasicAuth {
        username: "user".to_string(),
        password: "password".to_string(),
    }),
    webhook_secret: None,
};
}

HMAC Webhook Signature

For secure webhook verification:

#![allow(unused)]
fn main() {
let webhook = WebhookConfig {
    url: "https://your-app.com/webhook".to_string(),
    method: Some(HttpMethod::Post),
    headers: None,
    payload: Some(serde_json::json!({ "data": "sensitive" })),
    timeout_seconds: Some(30),
    retry_config: None,
    authentication: None,
    webhook_secret: Some("your-webhook-secret".to_string()),
};
}

The scheduler will include an X-Locci-Signature header with an HMAC-SHA256 signature. Verify on your server:

#![allow(unused)]
fn main() {
use hmac::{Hmac, Mac};
use sha2::Sha256;

type HmacSha256 = Hmac<Sha256>;

fn verify_signature(payload: &str, signature: &str, secret: &str) -> bool {
    let mut mac = HmacSha256::new_from_slice(secret.as_bytes())
        .expect("HMAC can take key of any size");
    mac.update(payload.as_bytes());

    let expected = hex::encode(mac.finalize().into_bytes());
    signature == expected
}
}

Execution History

#![allow(unused)]
fn main() {
let history = scheduler.get_task_history("task-id").await?;

println!("Total executions: {}", history.total);
for exec in &history.executions {
    println!("- {:?}: {:?}", exec.executed_at, exec.status);
    if let Some(ref error) = exec.error_message {
        println!("  Error: {}", error);
    }
}
}

Billing & Subscription

Get Current Subscription

#![allow(unused)]
fn main() {
let subscription = scheduler.get_subscription().await?;
println!("Plan: {:?}", subscription.plan);
println!("Status: {}", subscription.status);
}

Subscribe to a Plan

#![allow(unused)]
fn main() {
use locci_scheduler::SubscriptionPlan;

let subscription = scheduler.subscribe(
    SubscriptionPlan::Pro,
    "254712345678".to_string(), // M-Pesa phone number
).await?;
}

Get Usage

#![allow(unused)]
fn main() {
let usage = scheduler.get_usage().await?;
println!("Tasks created: {}", usage.current_usage.tasks_created);
println!("Webhook executions: {}", usage.current_usage.webhook_executions);
println!("API calls: {}", usage.current_usage.api_calls);
println!("Max tasks: {:?}", usage.limits.max_tasks);
}

Cancel Subscription

#![allow(unused)]
fn main() {
let subscription = scheduler.cancel_subscription().await?;
}

Error Handling

The SDK provides a comprehensive error type:

#![allow(unused)]
fn main() {
use locci_scheduler::SchedulerError;

match scheduler.create_task(options).await {
    Ok(task) => println!("Task created: {}", task.id),
    Err(SchedulerError::AuthenticationError(msg)) => {
        eprintln!("Authentication failed: {}", msg);
    }
    Err(SchedulerError::ValidationError(msg)) => {
        eprintln!("Invalid configuration: {}", msg);
    }
    Err(SchedulerError::NotFoundError(msg)) => {
        eprintln!("Resource not found: {}", msg);
    }
    Err(SchedulerError::RateLimitError(msg)) => {
        eprintln!("Rate limit exceeded: {}", msg);
    }
    Err(SchedulerError::ApiError { status, message }) => {
        eprintln!("API error ({}): {}", status, message);
    }
    Err(e) => eprintln!("Unexpected error: {}", e),
}
}

Error Types

#![allow(unused)]
fn main() {
pub enum SchedulerError {
    AuthenticationError(String),
    ValidationError(String),
    NotFoundError(String),
    RateLimitError(String),
    ApiError { status: u16, message: String },
    NetworkError(reqwest::Error),
    JsonError(serde_json::Error),
}
}

Types Reference

Task Status

#![allow(unused)]
fn main() {
pub enum TaskStatus {
    Active,
    Paused,
    Completed,
    Failed,
    Cancelled,
}
}

Execution Status

#![allow(unused)]
fn main() {
pub enum ExecutionStatus {
    Success,
    Failed,
    Retrying,
    TimedOut,
}
}

HTTP Methods

#![allow(unused)]
fn main() {
pub enum HttpMethod {
    Get,
    Post,
    Put,
    Patch,
    Delete,
}
}

Schedule Config

#![allow(unused)]
fn main() {
pub enum ScheduleConfig {
    Once {
        execute_at: DateTime<Utc>,
    },
    Recurring {
        cron_expression: String,
        timezone: Option<String>,
        end_date: Option<DateTime<Utc>>,
    },
    Interval {
        interval_seconds: u64,
        start_at: Option<DateTime<Utc>>,
        end_date: Option<DateTime<Utc>>,
    },
}
}

Subscription Plans

#![allow(unused)]
fn main() {
pub enum SubscriptionPlan {
    Free,
    Starter,
    Pro,
    Business,
}
}

Complete Example

use locci_scheduler::{
    LocciScheduler, SchedulerConfig, WebhookConfig, HttpMethod,
    PaginationOptions, SchedulerError,
};
use chrono::Utc;
use std::collections::HashMap;
use std::env;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize client
    let config = SchedulerConfig {
        base_url: env::var("LOCCI_SCHEDULER_URL")
            .unwrap_or_else(|_| "https://api.scheduler.locci.cloud".to_string()),
        api_token: env::var("LOCCI_SCHEDULER_TOKEN")
            .expect("LOCCI_SCHEDULER_TOKEN must be set"),
        timeout: 30000,
        retries: 3,
    };

    let scheduler = LocciScheduler::new(config)?;

    // Create webhook config
    let webhook = WebhookConfig {
        url: "https://httpbin.org/post".to_string(),
        method: Some(HttpMethod::Post),
        headers: Some({
            let mut h = HashMap::new();
            h.insert("Content-Type".to_string(), "application/json".to_string());
            h
        }),
        payload: Some(serde_json::json!({
            "message": "Hello from Locci Scheduler!",
            "timestamp": Utc::now().to_rfc3339()
        })),
        timeout_seconds: Some(30),
        retry_config: None,
        authentication: None,
        webhook_secret: None,
    };

    // Schedule a task
    let task = scheduler.schedule_interval(
        "Test Task".to_string(),
        webhook,
        60, // Every minute
        Some(Utc::now()),
        None,
        Some("Test task for demonstration".to_string()),
        None,
    ).await?;

    println!("Created task: {}", task.id);

    // List all tasks
    let tasks = scheduler.list_tasks(PaginationOptions {
        page: Some(1),
        per_page: Some(10),
    }).await?;

    println!("\nAll tasks ({}):", tasks.total);
    for t in &tasks.tasks {
        println!("  - {} ({:?})", t.name, t.status);
    }

    // Get usage information
    match scheduler.get_usage().await {
        Ok(usage) => {
            println!("\nUsage:");
            println!("  Tasks created: {}", usage.current_usage.tasks_created);
            println!("  Webhook executions: {}", usage.current_usage.webhook_executions);
            println!("  Plan: {:?}", usage.subscription.plan);
        }
        Err(e) => eprintln!("Failed to get usage: {}", e),
    }

    // Pause the task
    let paused_task = scheduler.pause_task(&task.id).await?;
    println!("\nTask paused: {:?}", paused_task.status);

    // Resume the task
    let resumed_task = scheduler.resume_task(&task.id).await?;
    println!("Task resumed: {:?}", resumed_task.status);

    // Delete the task
    scheduler.delete_task(&task.id).await?;
    println!("Task deleted");

    Ok(())
}

Resources