How to Create a Recurring Outlook Calendar Event With an End Date
If you need a recurring Outlook calendar event that ends on a specific date, the part people usually miss is this: in Microsoft Graph, recurrence is split into two objects:
recurrence.pattern= how it repeatsrecurrence.range= how long it keeps repeating
If you want the series to stop on a date, the key is:
"range": {
"type": "endDate",
"startDate": "2026-08-17",
"endDate": "2026-12-31"
}
That endDate does not replace the event’s normal start and end times. It only tells Outlook when the recurring series should stop.
Microsoft’s docs for recurring events are here:
- Schedule repeating appointments as recurring events in Outlook
- recurrencePattern resource
- recurrenceRange resource
The shape you actually need
A recurring Outlook event with an end date has three layers:
- The normal event fields:
subject,start,end,location, attendees, etc. recurrence.pattern: daily, weekly, monthly, yearlyrecurrence.range: no end, fixed number of occurrences, or specific end date
Here’s the smallest useful example.
Example: weekly recurring Outlook event with an end date
{
"subject": "Weekly Team Sync",
"start": {
"dateTime": "2026-08-17T09:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2026-08-17T09:30:00",
"timeZone": "Eastern Standard Time"
},
"recurrence": {
"pattern": {
"type": "weekly",
"interval": 1,
"daysOfWeek": ["Monday"]
},
"range": {
"type": "endDate",
"startDate": "2026-08-17",
"endDate": "2026-12-31"
}
}
}
That creates a Monday series starting August 17, 2026 and ending on December 31, 2026.
What each field means
pattern.type
Common values:
dailyweeklyabsoluteMonthlyrelativeMonthlyabsoluteYearlyrelativeYearly
pattern.interval
How often it repeats.
Examples:
1= every week2= every other week1withabsoluteMonthly= every month
pattern.daysOfWeek
Used for weekly and relative patterns.
Example:
"daysOfWeek": ["Monday", "Thursday"]
range.type
This is where the end condition lives.
Options:
noEndnumberedendDate
If you need the recurrence to stop on a calendar date, use endDate.
range.startDate
This is required for recurring series. In practice, it should match the date portion of the event’s first start.dateTime.
range.endDate
The date the recurring series stops. Outlook uses this as the end boundary for valid occurrences.
Example: recurring event on Monday and Thursday until a date
{
"subject": "Office Hours",
"start": {
"dateTime": "2026-08-17T15:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2026-08-17T16:00:00",
"timeZone": "Eastern Standard Time"
},
"recurrence": {
"pattern": {
"type": "weekly",
"interval": 1,
"daysOfWeek": ["Monday", "Thursday"]
},
"range": {
"type": "endDate",
"startDate": "2026-08-17",
"endDate": "2027-01-31"
}
}
}
Example: monthly recurring event with an end date
If you want “the 15th of every month until December 31,” use absoluteMonthly.
{
"subject": "Monthly Billing Review",
"start": {
"dateTime": "2026-08-15T11:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2026-08-15T12:00:00",
"timeZone": "Eastern Standard Time"
},
"recurrence": {
"pattern": {
"type": "absoluteMonthly",
"interval": 1,
"dayOfMonth": 15
},
"range": {
"type": "endDate",
"startDate": "2026-08-15",
"endDate": "2026-12-31"
}
}
}
POST request example
To create the event in Microsoft Graph:
POST https://graph.microsoft.com/v1.0/me/events
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN
With JavaScript:
const event = {
subject: 'Weekly Team Sync',
start: {
dateTime: '2026-08-17T09:00:00',
timeZone: 'Eastern Standard Time'
},
end: {
dateTime: '2026-08-17T09:30:00',
timeZone: 'Eastern Standard Time'
},
recurrence: {
pattern: {
type: 'weekly',
interval: 1,
daysOfWeek: ['Monday']
},
range: {
type: 'endDate',
startDate: '2026-08-17',
endDate: '2026-12-31'
}
}
};
await fetch('https://graph.microsoft.com/v1.0/me/events', {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(event)
});
The 4 mistakes that usually break this
1. Putting the end date in the wrong place
The series end date belongs in:
recurrence.range.endDate
Not in the event end.dateTime.
2. Forgetting range.startDate
Even if you already have start.dateTime, the recurrence range still needs its own startDate.
3. Mismatching start.dateTime and range.startDate
If the first event starts on 2026-08-17, your recurrence range should also start on 2026-08-17.
4. Mixing pattern fields across recurrence types
Examples:
dayOfMonthbelongs withabsoluteMonthlydaysOfWeekbelongs withweeklyor relative patternsindexis used for relative patterns like “first Monday”
If you want a fixed number of occurrences instead
Use numbered instead of endDate:
"range": {
"type": "numbered",
"startDate": "2026-08-17",
"numberOfOccurrences": 10
}
If you want it to never end
Use:
"range": {
"type": "noEnd",
"startDate": "2026-08-17"
}
Outlook recurring events are more annoying than Google Calendar
That’s the whole reason this trips people up. In Google Calendar, many developers are used to dropping an RRULE into one field. In Outlook via Microsoft Graph, recurrence is more structured:
- pattern
- range
- plus the normal event time block
Once you know that split, it’s straightforward.
Final copy-paste template
{
"subject": "Your event title",
"start": {
"dateTime": "2026-08-17T09:00:00",
"timeZone": "Eastern Standard Time"
},
"end": {
"dateTime": "2026-08-17T09:30:00",
"timeZone": "Eastern Standard Time"
},
"recurrence": {
"pattern": {
"type": "weekly",
"interval": 1,
"daysOfWeek": ["Monday"]
},
"range": {
"type": "endDate",
"startDate": "2026-08-17",
"endDate": "2026-12-31"
}
}
}
If you want an assistant that can do this kind of calendar work without you wiring Graph payloads by hand, Carly integrates with Outlook and can manage recurring calendar workflows across email, scheduling, tasks, and automation.
Ready to automate your busywork?
Carly schedules, researches, and briefs you—so you can focus on what matters.
See what people say
"Before Carly, I relied on a Calendly link, but the whole process felt impersonal and not very professional. Carly changed that by handling all the back-and-forth, so I'm no longer stuck in endless email threads trying to line up schedules.
Now Carly reaches out to candidates, shares my real-time availability, lets them pick a slot, then sends a Zoom link and drops it straight into my calendar. She sends reminders to both of us before each call, which has significantly reduced no-shows and last-minute confusion.
On top of scheduling, Carly acts like a full executive assistant, sending me my schedule the night before so I can prepare for each call. It reminds me of the old x.ai assistant, but Carly is noticeably smarter, faster, and better suited to my healthcare recruitment business."


