Scheduled Transactions

Setting up and managing scheduled transactions

Scheduled Transactions Guide

This guide covers setting up scheduled transactions for automated payments, subscriptions, and recurring transfers.

Overview

Scheduled transactions allow you to automate one-time or recurring transactions. Supported patterns include:

  • One-time: Execute a transaction at a specific future date/time
  • Daily: Execute every day at a specified time
  • Weekly: Execute weekly on a specific day
  • Monthly: Execute monthly on a specific date

Basic Setup

One-Time Scheduled Transaction

import { create } from 'cilantro-sdk/scheduled-transactions';

// Schedule a transaction for next week
const scheduledDate = new Date();
scheduledDate.setDate(scheduledDate.getDate() + 7);

const scheduled = await create('wallet-id', {
  transactionType: 'SEND_SOL',
  recurrenceType: 'ONE_TIME',
  scheduledAt: scheduledDate.toISOString(),
  toAddress: 'DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK',
  amount: 1000000000 // 1 SOL
});

console.log('Transaction scheduled:', scheduled.data.id);

Daily Recurring Transaction

// Schedule daily payments at 9 AM
const dailyPayment = await create('wallet-id', {
  transactionType: 'SEND_SOL',
  recurrenceType: 'DAILY',
  scheduledAt: '2024-01-01T09:00:00Z', // First execution time
  toAddress: 'recipient-address',
  amount: 50000000, // 0.05 SOL per day
  maxExecutions: 30 // Stop after 30 days
});

Weekly Recurring Transaction

// Schedule weekly subscription payment (every Monday)
const weeklySubscription = await create('wallet-id', {
  transactionType: 'SEND_SOL',
  recurrenceType: 'WEEKLY',
  scheduledAt: '2024-01-01T10:00:00Z', // Every Monday at 10 AM
  toAddress: 'subscription-recipient-address',
  amount: 1000000000 // 1 SOL per week
});

Monthly Recurring Transaction

// Schedule monthly salary payment (1st of each month)
const monthlySalary = await create('wallet-id', {
  transactionType: 'SEND_SOL',
  recurrenceType: 'MONTHLY',
  scheduledAt: '2024-01-01T00:00:00Z', // 1st of each month
  toAddress: 'employee-address',
  amount: 10000000000 // 10 SOL per month
});

Managing Scheduled Transactions

List All Scheduled Transactions

import { findAll } from 'cilantro-sdk/scheduled-transactions';

const scheduled = await findAll('wallet-id');

console.log('Total scheduled:', scheduled.data.length);

// Filter by status
const pending = scheduled.data.filter(tx => tx.status === 'pending');
const completed = scheduled.data.filter(tx => tx.status === 'completed');
const failed = scheduled.data.filter(tx => tx.status === 'failed');

Get Scheduled Transaction Details

import { findOne } from 'cilantro-sdk/scheduled-transactions';

const transaction = await findOne('wallet-id', 'scheduled-transaction-id');

console.log('Status:', transaction.data.status);
console.log('Next execution:', transaction.data.nextExecution);
console.log('Executions count:', transaction.data.executionCount);

Update Scheduled Transaction

import { update } from 'cilantro-sdk/scheduled-transactions';

// Update amount and schedule time
await update('wallet-id', 'scheduled-transaction-id', {
  scheduledAt: '2025-01-01T00:00:00Z',
  amount: 2000000000 // Increase to 2 SOL
});

Scheduled transactions cannot be updated once they enter 'processing' status. Make changes before the scheduled execution time.

Cancel Scheduled Transaction

import { cancel } from 'cilantro-sdk/scheduled-transactions';

// Cancel a pending scheduled transaction
await cancel('wallet-id', 'scheduled-transaction-id');

Use Cases

Subscription Payment System

async function setupSubscription(
  walletId: string,
  recipientAddress: string,
  monthlyAmount: number
) {
  // Create monthly subscription
  const subscription = await create(walletId, {
    transactionType: 'SEND_SOL',
    recurrenceType: 'MONTHLY',
    scheduledAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
    toAddress: recipientAddress,
    amount: monthlyAmount,
    metadata: {
      subscriptionId: 'sub-123',
      plan: 'premium'
    }
  });
  
  return subscription.data;
}

Automated Savings Plan

async function setupSavingsPlan(
  walletId: string,
  savingsWalletAddress: string,
  dailyAmount: number,
  durationDays: number
) {
  const savingsPlan = await create(walletId, {
    transactionType: 'SEND_SOL',
    recurrenceType: 'DAILY',
    scheduledAt: new Date().toISOString(),
    toAddress: savingsWalletAddress,
    amount: dailyAmount,
    maxExecutions: durationDays
  });
  
  return savingsPlan.data;
}

Payroll System

async function setupPayroll(
  walletId: string,
  employeeAddresses: string[],
  salaryAmount: number
) {
  const payrollTransactions = [];
  
  for (const address of employeeAddresses) {
    const transaction = await create(walletId, {
      transactionType: 'SEND_SOL',
      recurrenceType: 'MONTHLY',
      scheduledAt: '2024-01-01T00:00:00Z', // 1st of each month
      toAddress: address,
      amount: salaryAmount
    });
    
    payrollTransactions.push(transaction.data);
  }
  
  return payrollTransactions;
}

Monitoring and Status

Check Transaction Status

async function monitorScheduledTransactions(walletId: string) {
  const scheduled = await findAll(walletId);
  
  for (const tx of scheduled.data) {
    const details = await findOne(walletId, tx.id);
    
    console.log(`Transaction ${tx.id}:`);
    console.log(`- Status: ${details.data.status}`);
    console.log(`- Next execution: ${details.data.nextExecution}`);
    console.log(`- Executions: ${details.data.executionCount}`);
    
    if (details.data.status === 'failed') {
      console.error(`- Error: ${details.data.error}`);
      // Handle failed transaction
    }
  }
}

Handle Failed Transactions

async function handleFailedTransactions(walletId: string) {
  const scheduled = await findAll(walletId);
  const failed = scheduled.data.filter(tx => tx.status === 'failed');
  
  for (const tx of failed) {
    console.error(`Failed transaction: ${tx.id}`);
    
    // Option 1: Retry by updating schedule
    if (tx.recurrenceType !== 'ONE_TIME') {
      await update(walletId, tx.id, {
        scheduledAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString()
      });
    }
    
    // Option 2: Cancel and notify
    // await cancel(walletId, tx.id);
    // notifyUser(tx.id, 'Transaction failed');
  }
}

Best Practices

Verify Balance

Ensure wallet has sufficient balance before scheduling recurring transactions

Set Max Executions

Use maxExecutions to prevent infinite recurring transactions

Monitor Regularly

Regularly check transaction status to catch failures early

Handle Errors

Implement error handling for failed scheduled transactions

Next Steps

Scheduled Transactions | Cilantro Smart Wallet Docs | Cilantro Smart Wallet