Managing Schedules
Create schedules and add team members to on-call rotations.
Creating a Schedule
Section titled “Creating a Schedule”import { BeepsClient } from "@beepsdev/sdk";
const client = new BeepsClient({ apiKey: process.env.BEEPS_API_KEY,});
const schedule = await client.schedule.create({ name: "Weekly On-Call", relayId: "rly_abc123", // Schedule must belong to a relay type: "weekly", // or "daily" handoffDay: "monday", // Day of week for weekly schedules handoffTime: "09:00", // Time when rotation occurs (HH:MM format) // startAt: "2025-03-15T09:00:00.000Z", // Optional: omit to start immediately externalKey: "prod-oncall", // Optional: custom identifier});
console.log(`Created schedule: ${schedule.id}`);Daily Schedule
Section titled “Daily Schedule”const dailySchedule = await client.schedule.create({ name: "Daily On-Call", relayId: "rly_abc123", type: "daily", handoffDay: "monday", // Not used for daily schedules handoffTime: "09:00", // Rotates every day at this time});Weekly Schedule
Section titled “Weekly Schedule”const weeklySchedule = await client.schedule.create({ name: "Weekly On-Call", relayId: "rly_abc123", type: "weekly", handoffDay: "friday", // Rotates every Friday handoffTime: "17:00", // at 5:00 PM});If you omit startAt, beeps starts the schedule immediately. Set it explicitly when you want the schedule to begin in the future.
curl -X POST https://api.beeps.dev/v0/schedule \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Weekly On-Call", "relayId": "rly_abc123", "type": "weekly", "handoffDay": "monday", "handoffTime": "09:00", "externalKey": "prod-oncall" }'Response:
{ "schedule": { "id": "sch_xyz789", "organizationId": "org_abc123", "relayId": "rly_abc123", "name": "Weekly On-Call", "type": "weekly", "handoffDay": "monday", "handoffTime": "09:00", "startAt": "2025-01-15T10:30:00Z", "externalKey": "prod-oncall", "createdAt": "2025-01-15T10:30:00Z", "updatedAt": "2025-01-15T10:30:00Z", "deletedAt": null }}Listing Schedules
Section titled “Listing Schedules”const schedules = await client.schedule.list();
console.log(`Found ${schedules.length} schedules:`);schedules.forEach((schedule) => { console.log(`- ${schedule.name} (${schedule.type})`);});curl -X GET https://api.beeps.dev/v0/schedule \ -H "Authorization: Bearer YOUR_API_KEY"Response:
{ "schedules": [ { "id": "sch_xyz789", "organizationId": "org_abc123", "relayId": "rly_abc123", "name": "Weekly On-Call", "type": "weekly", "handoffDay": "monday", "handoffTime": "09:00", "startAt": "2025-01-15T10:30:00Z", "externalKey": "prod-oncall", "createdAt": "2025-01-15T10:30:00Z", "updatedAt": "2025-01-15T10:30:00Z", "deletedAt": null } ]}Adding Schedule Members
Section titled “Adding Schedule Members”Members are added to the rotation in the order they’re added. New members usually join at the next handoff boundary so the current on-call assignment is not interrupted. If the schedule has not started yet, they become active at startAt. If the schedule is active but currently has no active members, they become active immediately. You can add members by email address or user ID.
// Add by email addressconst member1 = await client.schedule.addMember(schedule.id, { email: "alice@example.com",});console.log(`Added ${member1.userId} to schedule`);
const member2 = await client.schedule.addMember(schedule.id, { email: "bob@example.com",});console.log(`Added ${member2.userId} to schedule`);
// Or add by user IDconst member3 = await client.schedule.addMember(schedule.id, { userId: "usr_charlie",});# Add by emailcurl -X POST https://api.beeps.dev/v0/schedule/sch_xyz789/members \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "email": "alice@example.com" }'
# Or by user IDcurl -X POST https://api.beeps.dev/v0/schedule/sch_xyz789/members \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "userId": "usr_alice" }'Response:
{ "member": { "id": "scm_abc123", "scheduleId": "sch_xyz789", "userId": "usr_alice", "createdAt": "2025-01-15T10:35:00Z", "effectiveAt": "2025-01-20T09:00:00Z", "removedAt": null }}Getting Current On-Call User
Section titled “Getting Current On-Call User”const onCall = await client.schedule.getOnCall(schedule.id);
console.log(`Current on-call: ${onCall.email}`);console.log(`User ID: ${onCall.userId}`);console.log(`Assignment #: ${onCall.assignmentNumber}`);Safe Method
Section titled “Safe Method”const result = await client.schedule.getOnCallSafe(schedule.id);
if (result.error) { console.error("Failed to get on-call:", result.error.message);} else { console.log(`On-call: ${result.data.email}`);}curl -X GET https://api.beeps.dev/v0/schedule/sch_xyz789/on-call \ -H "Authorization: Bearer YOUR_API_KEY"Response:
{ "onCall": { "userId": "usr_alice", "email": "alice@example.com", "assignmentNumber": 7, "scheduleId": "sch_xyz789" }}Type Definitions
Section titled “Type Definitions”CreateScheduleInput
Section titled “CreateScheduleInput”type CreateScheduleInput = { name: string; // Schedule name relayId: string; // Parent relay ID type: "daily" | "weekly"; // Rotation frequency handoffDay: | "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday" | "sunday"; // Day of week (used for weekly schedules) handoffTime: string; // Time of day in HH:MM format (24-hour) startAt?: string | Date; // Optional: omit to start immediately externalKey?: string; // Optional custom identifier};Schedule
Section titled “Schedule”type Schedule = { id: string; organizationId: string; relayId: string; name: string; type: "daily" | "weekly"; handoffDay: | "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday" | "sunday"; handoffTime: string; startAt: string; externalKey: string | null; createdAt: string; updatedAt: string; deletedAt: string | null;};AddScheduleMemberInput
Section titled “AddScheduleMemberInput”type AddScheduleMemberInput = | { userId: string } // Add by user ID | { email: string }; // Add by email addressScheduleMember
Section titled “ScheduleMember”type ScheduleMember = { id?: string; scheduleId: string; userId: string; createdAt?: string; effectiveAt?: string; removedAt?: string | null;};BeepsUser
Section titled “BeepsUser”type BeepsUser = { userId: string; // User ID of the person currently on-call email: string; // Email address assignmentNumber: number | null; // Current generated assignment index (null when schedule has no members) scheduleId: string; // Schedule ID isOverride?: boolean; // True if user is on-call via schedule override overrideId?: string; // ID of the schedule override (if applicable)};Best Practices
Section titled “Best Practices”Always set externalKey for idempotent configuration. All times are in UTC. See Best Practices for details.
Common Patterns
Section titled “Common Patterns”Setting Up a New Team
Section titled “Setting Up a New Team”const relay = await client.relay.create({ name: "Backend Team Alerts",});
const schedule = await client.schedule.create({ name: "Backend Weekly Rotation", relayId: relay.id, type: "weekly", handoffDay: "monday", handoffTime: "09:00",});
const teamEmails = ["alice@example.com", "bob@example.com", "charlie@example.com"];for (const email of teamEmails) { await client.schedule.addMember(schedule.id, { email });}
await client.relay.rules.create(relay.id, { name: "Notify on-call engineer", ruleType: "schedule_notify", config: { scheduleId: schedule.id, },});Checking Who’s On Call
Section titled “Checking Who’s On Call”const onCall = await client.schedule.getOnCall(schedule.id);console.log(`${onCall.email} is currently on-call`);