New API availability endpoint on production! <@U03...
# api
a
New API availability endpoint on production! @Varun Krishnamurthy @Vikram @Octavian Balatel I know you guys where waiting for this! Couldn’t have make it without @zomars help tbh but here it is!
<https://api.cal.com/v1/availability?apiKey=YOUR_API_KEY_HERE&dateFrom=2022-06-14&dateTo=2022-06-17&userId=1>
Postman docs: https://documenter.getpostman.com/view/20666831/Uz5ArJni#8333a1d5-9df6-4134-b654-8ede7becafb5
🙏 4
❤️ 1
🙌 2
v
thank you so much @Agusti! very excited to integrate with this 😄
🚀 2
a
Wrong thread, added postman link on the main post, here an example response:
Copy code
// 20220615003519
// <https://api.cal.com/v1/availability?apiKey=,,,&dateFrom=2022-06-14&dateTo=2022-06-17&userId=1>

{
  "busy": [
    {
      "start": "2022-06-14T13:00:00.000Z",
      "end": "2022-06-14T13:15:00.000Z"
    },
    {
      "start": "2022-06-14T14:00:00.000Z",
      "end": "2022-06-14T14:30:00.000Z"
    },
    {
      "start": "2022-06-15T09:30:00.000Z",
      "end": "2022-06-15T10:00:00.000Z"
    },
    {
      "start": "2022-06-14T13:30:00.000Z",
      "end": "2022-06-14T13:45:00.000Z"
    },
    {
      "start": "2022-06-14T09:30:00.000Z",
      "end": "2022-06-14T10:00:00.000Z"
    },
    {
      "start": "2022-06-15T10:00:00.000Z",
      "end": "2022-06-15T10:15:00.000Z"
    },
    {
      "start": "2022-06-14T09:30:00.000Z",
      "end": "2022-06-14T10:00:00.000Z"
    },
    {
      "start": "2022-06-14T13:00:00.000Z",
      "end": "2022-06-14T13:15:00.000Z"
    },
    {
      "start": "2022-06-14T13:30:00.000Z",
      "end": "2022-06-14T13:45:00.000Z"
    },
    {
      "start": "2022-06-14T14:00:00.000Z",
      "end": "2022-06-14T14:30:00.000Z"
    },
    {
      "start": "2022-06-14T16:30:00.000Z",
      "end": "2022-06-14T17:00:00.000Z"
    },
    {
      "start": "2022-06-15T09:00:00.000Z",
      "end": "2022-06-15T10:15:00.000Z"
    },
    {
      "start": "2022-06-15T18:00:00.000Z",
      "end": "2022-06-15T18:15:00.000Z"
    },
    {
      "start": "2022-06-16T09:00:00.000Z",
      "end": "2022-06-16T09:30:00.000Z"
    },
    {
      "start": "2022-06-15T14:15:00.000Z",
      "end": "2022-06-15T15:15:00.000Z"
    },
    {
      "start": "2022-06-15T23:00:00.000Z",
      "end": "2022-06-16T23:00:00.000Z"
    }
  ],
  "timeZone": "GMT",
  "workingHours": [
    {
      "days": [
        1,
        2,
        3,
        4,
        5
      ],
      "startTime": 540,
      "endTime": 1020
    }
  ]
}
v
got it, thanks. just to confirm - the API is titled availabilities, but the response "start" and "end" data is busy (*filled*/*unavailable*) times or available times?
z
Those are the blocked timeslots as we use them in our webapp
v
i see. @zomars @Agusti what is the simplest way to get all the available time slots? trying to determine the cleanest way via API to surface available booking times within a certain start and end time period to external users. right now, it seems I must use this API to "construct" available timeslots myself by, for each eligible date, determining if its a "working day" and what the "working hours" from that are. and at that point, removing busy times from those periods. or is there a working "schedules" API that surfaces the user's schedule, and then I'd essentially subtract busy times from the schedule?
a
Maybe checking useSlots (how we use this same API in web helps you with your implementation @Varun Krishnamurthy?
<http://cal.com/apps/web/lib/hooks/useSlots.ts|cal.com/apps/web/lib/hooks/useSlots.ts>
from line 169
Copy code
users.map((user) => fetch(`/api/availability/${user.username}?${query}`).then(handleAvailableSlots))
v
I am not able to view that file (getting a 404) 😞
a
its just the path, not a working link let me look for gh
v
thanks for sharing. will dig into this. by the way, how should I parse these
startTime
and
endTime
times in the
workingHours
object?
Copy code
"startTime": 540,
      "endTime": 1020
a
1440 a day I think those are minutes
Yeah that’s a 9 to 5 if you divide by 60
v
oh i see. so those values can range from 0 to 1440 essentially?
a
540/60 = 9:00 1020/60 = 17:00
yup that’s it
Will add this to docs so it’s more obvious
Thanks for the feedback @Varun Krishnamurthy
v
thank you Agusti. this is definitely helpful. overall, though, I feel an "Availabilities" API should intuitively surface available time slots rather than busy time slots so that consumers of the API don't need to construct availabilities themselves. what are your thoughts on this @Agusti @zomars (+ @Vikram)? 🙂
v
I like the idea but this would have to be per event so the slots returned follow the spec of the event. Im thinking about factors like length of meeting, buffer times, etc.
until we can do that its almost easier to just construct this ourselves per event. @Varun Krishnamurthy I imagine we are going to have to build this helper function anyways. Just something that takes a event from the
event-types
api and generates "available" times using the availability api. I have something super hacky that is hardcoded to work with a single event but I can try to generalize it and make it available
v
@Vikram that's a fair point! thanks for your response. would you feel comfortable sharing a gist of the code/logic you've created for the single event for building available times? i figure i essentially need to do the same thing to start, so curious to see how you approached it - no worries if is super hacky 🙂
v
Basically im iterating through a given date 1 hour at a time and determining if its available
Copy code
date.setHours(workingHours.startTime)                                                                                                                                                                                                                                                                                         
while (date.getHours() < workingHours.endTime) {                                                                                                                                                                                                                                                                              
  const startDateTime = new Date(date);                                                                                                                                                                                                                                                                                       
  date.setHours(date.getHours() + 1)                                                                                                                                                                                                                                                                                          
  const endDateTime = date;                                                                                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                                                              
  const slotTaken = availabilties?.busy?.some(busy => {                                                                                                                                                                                                                                                                       
    return dateIsBetween(startDateTime, new Date(busy.start), new Date(busy.end)) || dateIsBetween(endDateTime, new Date(busy.start), new Date(busy.end));                                                                                                                                                                    
  })                                                                                                                                                                                                                                                                                                                          
  if (!slotTaken) {                                                                                                                                                                                                                                                                                                           
    const slot = {                                                                                                                                                                                                                                                                                                            
      name: `${startDateTime.toLocaleTimeString('en-us', timeFormatOptions)} to ${endDateTime.toLocaleTimeString('en-us', timeFormatOptions)}`,                                                                                                                                                                               
      lengthInMinutes: 60,                                                                                                                                                                                                                                                                                                    
      startTime: startDateTime.toISOString(),                                                                                                                                                                                                                                                                                 
      endTime: endDateTime.toISOString(),                                                                                                                                                                                                                                                                                     
    }                                                                                                                                                                                                                                                                                                                             slots.push(slot);                                                                                                                                                                                                                                                                                                         
  }                                                                                                                                                                                                                                                                                                                           
}
this is a snippet but should give u a general idea
v
thanks a bunch @Vikram - this is a great reference point! figured i'd need to take a similar approach 😄
v
if you end up making a generic helper that works with all event types let me know
v
definitely, will do. at the moment, we only use 1 event type, but when that changes, we will definitely have to generalize, so I'll keep you posted 🙂
v
we are in the same boat i dont want to have to write code everytime we decide to change the event at all
lazyness is a virtue
v
😄 couldn't agree more
z
Makes sense. I’m just guessing since I didn't work on the slots logic. But I think it's constructed in the client to take browser formatting and timezone considerations. There's plenty of room to improve tho