iCalendar Parser API
Parse .ics calendars into JSON events, expand RRULE recurrences in a date range, convert time zones, merge calendars and find free slots.
Send iCalendar text as ics (or as a raw text/calendar body), a file, a url / urls (public feeds, webcal:// accepted, up to 5 per request) or calendars (an array of texts or {url} objects) to merge several calendars. Each event comes back with summary, description, location, URL, status, transparency, categories, organizer and attendees, alarms, start / end in the target timezone (ISO 8601 with offset; YYYY-MM-DD for all-day events, end exclusive), start_utc / end_utc, duration and the original time zone. Times with a TZID use the IANA zone, or the calendar’s own VTIMEZONE when the name is not an IANA one (Outlook), a few Windows names are mapped, and floating times are read in the target zone.
With from / to (dates are inclusive, read in the target zone) recurring series are expanded: RRULE with FREQ (minutely to yearly), INTERVAL, COUNT, UNTIL, BYDAY with ordinals (1FR, -1SU), BYMONTHDAY, BYMONTH, BYYEARDAY, BYHOUR / BYMINUTE / BYSECOND, BYSETPOS and WKST, plus RDATE, EXDATE and moved or cancelled instances (RECURRENCE-ID). Recurrences keep their wall-clock time across daylight-saving changes. Without a range, events are returned as stored with their rrule (expand=true lists the first occurrences); limit caps the output (default 1000, max 5000).
free_slots=true merges the busy time of all calendars (cancelled and transparent events ignored, all-day events only with all_day_busy=true) and returns the free intervals inside working hours (work_start, work_end, work_days as ISO weekdays, min_minutes) for up to 62 days (default: 7 days from today). Nothing is stored.
Parameters
| Name | In | Type | Required | Default | |
|---|---|---|---|---|---|
ics | body | string | no | iCalendar text (or send it as a raw text/calendar body). | |
file | body | file | no | .ics file (multipart). | |
url | body|query | string | no | Public .ics / webcal feed URL; urls for several (max 5). | |
calendars | body | array | no | Several calendars to merge: texts or {url} / {ics} objects (max 10). | |
timezone | body|query | string | no | Target IANA zone. Default: the calendar’s X-WR-TIMEZONE, else UTC. | |
from | body|query | string | no | Range start (YYYY-MM-DD or ISO date-time); turns expansion on. | |
to | body|query | string | no | Range end (a date is inclusive). Default: 1 year after from. | |
expand | body|query | boolean | no | Expand recurrences (default: on when a range is given). | |
limit | body|query | number | no | 1000 | Maximum events returned (1–5000). |
include_cancelled | body|query | boolean | no | false | Keep events with STATUS:CANCELLED. |
free_slots | body|query | boolean | no | false | Also return free time within working hours. |
work_start | body|query | string | no | 09:00 | Working day start (HH:MM). |
work_end | body|query | string | no | 17:00 | Working day end (HH:MM). |
work_days | body|query | string | no | 1-5 | ISO weekdays, 1 = Monday … 7 = Sunday, e.g. 1-5 or 1-6. |
min_minutes | body|query | number | no | 30 | Shortest free slot returned (5–1440). |
all_day_busy | body|query | boolean | no | false | Count all-day events as busy. |
Example
curl -X POST "https://apibox.io.vn/v1/ics-parse" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"ics":"BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//APIBox//demo//VI\r\nX-WR-CALNAME:Nhóm dự án\r\nX-WR-TIMEZONE:Asia/Ho_Chi_Minh\r\nBEGIN:VEVENT\r\nUID:standup@example.vn\r\nDTSTART;TZID=Asia/Ho_Chi_Minh:20261116T090000\r\nDTEND;TZID=Asia/Ho_Chi_Minh:20261116T093000\r\nRRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=12\r\nSUMMARY:Họp đầu ngày\r\nLOCATION:Phòng 3\r\nEND:VEVENT\r\nBEGIN:VEVENT\r\nUID:demo@example.vn\r\nDTSTART:20261117T070000Z\r\nDTEND:20261117T083000Z\r\nSUMMARY:Demo khách hàng\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n","from":"2026-11-16","to":"2026-11-17","free_slots":true,"work_start":"08:30","work_end":"17:30"}'const res = await fetch('https://apibox.io.vn/v1/ics-parse', {
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"ics": "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//APIBox//demo//VI\r\nX-WR-CALNAME:Nhóm dự án\r\nX-WR-TIMEZONE:Asia/Ho_Chi_Minh\r\nBEGIN:VEVENT\r\nUID:standup@example.vn\r\nDTSTART;TZID=Asia/Ho_Chi_Minh:20261116T090000\r\nDTEND;TZID=Asia/Ho_Chi_Minh:20261116T093000\r\nRRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=12\r\nSUMMARY:Họp đầu ngày\r\nLOCATION:Phòng 3\r\nEND:VEVENT\r\nBEGIN:VEVENT\r\nUID:demo@example.vn\r\nDTSTART:20261117T070000Z\r\nDTEND:20261117T083000Z\r\nSUMMARY:Demo khách hàng\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n",
"from": "2026-11-16",
"to": "2026-11-17",
"free_slots": true,
"work_start": "08:30",
"work_end": "17:30"
}),
});
const data = await res.json();
console.log(data);import requests
res = requests.post(
"https://apibox.io.vn/v1/ics-parse",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"ics": "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//APIBox//demo//VI\r\nX-WR-CALNAME:Nhóm dự án\r\nX-WR-TIMEZONE:Asia/Ho_Chi_Minh\r\nBEGIN:VEVENT\r\nUID:standup@example.vn\r\nDTSTART;TZID=Asia/Ho_Chi_Minh:20261116T090000\r\nDTEND;TZID=Asia/Ho_Chi_Minh:20261116T093000\r\nRRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=12\r\nSUMMARY:Họp đầu ngày\r\nLOCATION:Phòng 3\r\nEND:VEVENT\r\nBEGIN:VEVENT\r\nUID:demo@example.vn\r\nDTSTART:20261117T070000Z\r\nDTEND:20261117T083000Z\r\nSUMMARY:Demo khách hàng\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", "from": "2026-11-16", "to": "2026-11-17", "free_slots": True, "work_start": "08:30", "work_end": "17:30"},
timeout=30,
)
print(res.json())<?php
$ch = curl_init('https://apibox.io.vn/v1/ics-parse');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => ['Authorization: Bearer YOUR_API_KEY', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => '{"ics":"BEGIN:VCALENDAR\\r\\nVERSION:2.0\\r\\nPRODID:-//APIBox//demo//VI\\r\\nX-WR-CALNAME:Nhóm dự án\\r\\nX-WR-TIMEZONE:Asia/Ho_Chi_Minh\\r\\nBEGIN:VEVENT\\r\\nUID:standup@example.vn\\r\\nDTSTART;TZID=Asia/Ho_Chi_Minh:20261116T090000\\r\\nDTEND;TZID=Asia/Ho_Chi_Minh:20261116T093000\\r\\nRRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=12\\r\\nSUMMARY:Họp đầu ngày\\r\\nLOCATION:Phòng 3\\r\\nEND:VEVENT\\r\\nBEGIN:VEVENT\\r\\nUID:demo@example.vn\\r\\nDTSTART:20261117T070000Z\\r\\nDTEND:20261117T083000Z\\r\\nSUMMARY:Demo khách hàng\\r\\nEND:VEVENT\\r\\nEND:VCALENDAR\\r\\n","from":"2026-11-16","to":"2026-11-17","free_slots":true,"work_start":"08:30","work_end":"17:30"}',
]);
$response = curl_exec($ch);
print_r(json_decode($response, true));Response
{
"calendars": [
{
"index": 0,
"source": "ics",
"name": "Nhóm dự án",
"timezone": "Asia/Ho_Chi_Minh",
"prodid": "-//APIBox//demo//VI",
"method": null,
"events": 2
}
],
"timezone": "Asia/Ho_Chi_Minh",
"range": {
"from": "2026-11-16T00:00:00+07:00",
"to": "2026-11-18T00:00:00+07:00"
},
"expanded": true,
"count": 2,
"truncated": false,
"events": [
{
"uid": "standup@example.vn",
"summary": "Họp đầu ngày",
"start": "2026-11-16T09:00:00+07:00",
"end": "2026-11-16T09:30:00+07:00",
"start_utc": "2026-11-16T02:00:00.000Z",
"end_utc": "2026-11-16T02:30:00.000Z",
"all_day": false,
"duration_minutes": 30,
"timezone": "Asia/Ho_Chi_Minh",
"location": "Phòng 3",
"recurring": true
},
{
"uid": "demo@example.vn",
"summary": "Demo khách hàng",
"start": "2026-11-17T14:00:00+07:00",
"end": "2026-11-17T15:30:00+07:00",
"start_utc": "2026-11-17T07:00:00.000Z",
"end_utc": "2026-11-17T08:30:00.000Z",
"all_day": false,
"duration_minutes": 90,
"timezone": "UTC"
}
],
"free_slots": {
"work_hours": {
"start": "08:30",
"end": "17:30",
"days": [
1,
2,
3,
4,
5
]
},
"min_minutes": 30,
"busy": [
{
"start": "2026-11-16T09:00:00+07:00",
"end": "2026-11-16T09:30:00+07:00"
},
{
"start": "2026-11-17T14:00:00+07:00",
"end": "2026-11-17T15:30:00+07:00"
}
],
"slots": [
{
"start": "2026-11-16T08:30:00+07:00",
"end": "2026-11-16T09:00:00+07:00",
"minutes": 30
},
{
"start": "2026-11-16T09:30:00+07:00",
"end": "2026-11-16T17:30:00+07:00",
"minutes": 480
},
{
"start": "2026-11-17T08:30:00+07:00",
"end": "2026-11-17T14:00:00+07:00",
"minutes": 330
},
{
"start": "2026-11-17T15:30:00+07:00",
"end": "2026-11-17T17:30:00+07:00",
"minutes": 120
}
],
"total_free_minutes": 960
}
}
Use cases
- Show a Google, Outlook or iCloud calendar feed on your website as JSON
- List every occurrence of recurring meetings or classes in a month
- Find common free time across several people’s calendars
- Import .ics files into your own booking or HR system
FAQ
Why do some recurring events look one hour off?
They do not: occurrences keep their local time in the event’s time zone, so the UTC time moves when daylight saving starts or ends, as calendar apps do.
Which RRULE parts are not supported?
BYWEEKNO and FREQ=SECONDLY; such series return only their first instance with a warning.
Is my calendar stored?
No. Calendars are parsed in memory for the request and discarded; URL feeds are fetched each time.
Related APIs
JSON Validator
Check JSON syntax with exact line and column of errors, and validate data against a JSON Schema (draft 4, 7, 2019-09 or 2020-12).
{ }JSON Formatter
Pretty print JSON with 0-8 spaces or tabs, minify it, or sort object keys recursively. Syntax errors are reported with line and column.
CSVCSV to JSON
Convert CSV into an array of JSON objects using the header row, with delimiter auto-detection, number and boolean typing, and row-level errors.