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