GuidesCreate Your First Schedule

Create Your First Schedule

Step-by-step guide to creating your first payment schedule.

Prerequisites

  • Veil SDK installed
  • wallet with SOL for fees
  • devnet USDC or another allowed devnet mint
  • basic TypeScript knowledge

Step 1: Setup

import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import { Wallet, BN } from "@coral-xyz/anchor";
import { VeilClient } from "@veil-dev/sdk";
 
const connection = new Connection("https://api.devnet.solana.com");
const keypair = Keypair.fromSecretKey(/* your secret key */);
const wallet = new Wallet(keypair);
const client = new VeilClient({ connection, wallet });

Step 2: Create Vault

const USDC_MINT = new PublicKey("4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU");
 
await client.initVault(USDC_MINT);
console.log("Vault created!");

Step 3: Deposit Tokens

const amount = new BN(10_000_000); // 10 USDC (6 decimals)
 
await client.deposit(amount, USDC_MINT);
console.log("Deposited 10 USDC");

Step 4: Define Recipients

const recipients = [
  {
    address: new PublicKey("Recipient1Address..."),
    amount: 100_000n, // 0.1 USDC
  },
  {
    address: new PublicKey("Recipient2Address..."),
    amount: 200_000n, // 0.2 USDC
  },
  {
    address: new PublicKey("Recipient3Address..."),
    amount: 200_000n, // 0.2 USDC
  },
];

Step 5: Create Schedule

const { signature, scheduleId, merkleRoot } =
  await client.createScheduleFromRecipients({
    tokenMint: USDC_MINT,
    recipients,
    intervalSecs: 86400, // Daily (24 hours)
    reservedAmount: new BN(5_000_000), // Reserve 5 USDC total
    perExecutionAmount: new BN(500_000), // Pay 0.5 USDC per cycle
  });
 
console.log("Schedule created!");
console.log("Signature:", signature);
console.log("Schedule ID:", scheduleId);
console.log("Merkle Root:", merkleRoot);

Step 6: Register with Coordinator

Register your schedule for automatic execution:

import { getSchedulePda, getVaultPda } from "@veil-dev/sdk";
 
const [vaultPda] = getVaultPda(wallet.publicKey, USDC_MINT);
const [schedulePda] = getSchedulePda(vaultPda, scheduleId);
const COORDINATOR_URL = "http://localhost:3001/api";
 
const response = await fetch(`${COORDINATOR_URL}/schedules`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    schedulePda: schedulePda.toString(),
    scheduleId: Array.from(scheduleId),
    vaultEmployer: wallet.publicKey.toString(),
    tokenMint: USDC_MINT.toString(),
    recipients: recipients.map((recipient) => ({
      address: recipient.address.toString(),
      amount: recipient.amount.toString(),
    })),
  }),
});
 
const data = await response.json();
console.log("Registered:", data);

If you retry the exact same registration payload, the coordinator returns a successful response with alreadyRegistered: true.

Step 7: Edit a Schedule

Schedules can be edited after pausing. After an edit, re-register the updated recipient payload with the coordinator, then resume the schedule.

await client.pauseSchedule(schedulePda, true);
 
const updatedRecipients = [
  { address: new PublicKey("Recipient1Address..."), amount: 150_000n },
  { address: new PublicKey("Recipient2Address..."), amount: 250_000n },
];
 
await client.updateScheduleFromRecipients({
  schedulePda,
  recipients: updatedRecipients,
  intervalSecs: 86400,
  reservedAmount: new BN(5_000_000),
});
 
await fetch(`${COORDINATOR_URL}/schedules`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    schedulePda: schedulePda.toString(),
    scheduleId: Array.from(scheduleId),
    vaultEmployer: wallet.publicKey.toString(),
    tokenMint: USDC_MINT.toString(),
    recipients: updatedRecipients.map((recipient) => ({
      address: recipient.address.toString(),
      amount: recipient.amount.toString(),
    })),
  }),
});
 
await client.pauseSchedule(schedulePda, false);

Complete Example

import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import { Wallet, BN } from "@coral-xyz/anchor";
import { VeilClient, getVaultPda, getSchedulePda } from "@veil-dev/sdk";
 
async function createFirstSchedule() {
  const connection = new Connection("https://api.devnet.solana.com");
  const keypair = Keypair.fromSecretKey(/* your secret key */);
  const wallet = new Wallet(keypair);
  const client = new VeilClient({ connection, wallet });
 
  const USDC = new PublicKey("4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU");
 
  await client.initVault(USDC);
  await client.deposit(new BN(10_000_000), USDC);
 
  const recipients = [
    { address: new PublicKey("..."), amount: 100_000n },
    { address: new PublicKey("..."), amount: 200_000n },
  ];
 
  const { scheduleId } = await client.createScheduleFromRecipients({
    tokenMint: USDC,
    recipients,
    intervalSecs: 86400,
    reservedAmount: new BN(5_000_000),
    perExecutionAmount: new BN(300_000),
  });
 
  const [vaultPda] = getVaultPda(wallet.publicKey, USDC);
  const [schedulePda] = getSchedulePda(vaultPda, scheduleId);
 
  const schedule = await client.getSchedule(schedulePda);
  console.log("Schedule status:", schedule?.status);
}
 
createFirstSchedule();

Dashboard Shortcut

The employer dashboard can walk you through the same flow without writing code:

  • create the vault
  • deposit the mint balance
  • upload recipients via CSV or Excel
  • save the payout setup as a local template for this wallet
  • register the schedule with the coordinator automatically