DEV Community

Qasim Muhammad
Qasim Muhammad

Posted on

Recruiting Agent: Interview Scheduling Pipeline

A candidate finishes your take-home on a Friday afternoon. By the time a recruiter has cross-referenced three interviewers' calendars and emailed back a slot, it's Wednesday — and the candidate already has another offer in hand. Interview scheduling loses good people not because anyone is careless, but because the coordination loop is human-speed.

Here's a pipeline that takes the human out of that loop entirely: candidates pick their own slot from a booking page, the load spreads across your panel automatically, every call gets a conferencing link and a recording bot, and a structured transcript lands in your ATS after each interview. It's built on the Nylas Scheduler, Calendar, and Notetaker APIs, and it pairs naturally with Agent Accounts (currently in beta) if you want the recruiting side to run from its own dedicated mailbox instead of a recruiter's inbox.

The shape of the pipeline

Candidate visits a scheduling page → Scheduler assigns an interviewer via round-robin → an event lands on that interviewer's calendar with a meeting link → a booking.created webhook creates the record in your ATS → Notetaker joins the call → a notetaker.media webhook delivers transcript, summary, and action items → you attach them to the candidate's record.

The interesting part is that none of these steps need a person. The full recipe lives in the interview scheduling pipeline tutorial.

Round-robin that's actually fair

You define the panel once, in a scheduling Configuration:

curl --request POST \
  --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/scheduling/configurations' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "requires_session_auth": false,
    "participants": [
      { "name": "Sarah Kim", "email": "sarah.kim@yourcompany.com", "is_organizer": true,
        "availability": { "calendar_ids": ["primary"] }, "booking": { "calendar_id": "primary" } },
      { "name": "Marcus Johnson", "email": "marcus.johnson@yourcompany.com",
        "availability": { "calendar_ids": ["primary"] }, "booking": { "calendar_id": "primary" } }
    ],
    "availability": {
      "duration_minutes": 45,
      "availability_rules": { "availability_method": "max-fairness" }
    },
    "event_booking": { "title": "Interview with {{invitee_name}}" }
  }'
Enter fullscreen mode Exit fullscreen mode

Two distribution strategies exist, and the choice matters more than it looks:

  • max-fairness keeps interview counts balanced — whoever was booked least recently gets the next candidate. The tradeoff: candidates see fewer open slots.
  • max-availability shows the most possible slots and assigns whoever's free. High-volume teams usually pick this one because candidates book faster.

One practical limit from the docs: keep a Configuration under 10 interviewers. Bigger panels should split by interview stage or role.

Recording without a notetaker on payroll

Attach Notetaker to the Configuration and every booked call gets recorded, transcribed, and summarized. The detail that makes this useful for hiring specifically is custom_instructions — you tell the summarizer to focus on technical skills demonstrated, communication quality, and follow-up topics, so output maps to your scorecard instead of being a generic recap.

Two hard constraints to design around:

  • Media URLs expire 60 minutes after the notetaker.media webhook fires. Download immediately.
  • Files are deleted after 14 days. Hiring cycles often run longer than that, so an automated download-and-store step isn't optional.

Also: the bot joins as a non-signed-in participant. If nobody admits it from the lobby within 10 minutes, it gives up with failed_entry and the recording is gone. For automated pipelines, configure Meet/Teams/Zoom to let anonymous participants in — "Anyone with the link can join" for Meet, "Anonymous users can join" for Teams, waiting room off for Zoom.

Getting the link in front of candidates

The Configuration alone doesn't give candidates anything to click. The fastest option is a Nylas-hosted page — add a slug and you're done:

curl --request PUT \
  --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/scheduling/configurations/<CONFIGURATION_ID>' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{ "slug": "interview-engineering-team" }'
Enter fullscreen mode Exit fullscreen mode

The booking page is now live at book.nylas.com/interview-engineering-team. Drop that URL into recruiter emails or your ATS's candidate templates and you have a working self-booking flow with zero frontend work.

If you'd rather keep candidates on your own careers site, embed the scheduling UI instead:

<script src="https://cdn.jsdelivr.net/npm/@nylas/react@latest/dist/cdn/nylas-scheduling/nylas-scheduling.es.js"></script>

<nylas-scheduling configuration-id="<CONFIGURATION_ID>"></nylas-scheduling>
Enter fullscreen mode Exit fullscreen mode

The web component handles date selection, time slots, the booking form, and confirmation. Round-robin assignment and Notetaker consent apply automatically — the embedded version isn't a second-class citizen. (For production, pin the package to a specific version instead of @latest and add a Subresource Integrity hash so a CDN change can't alter what your careers page loads.)

Wiring the webhooks into your ATS

Subscribe to three triggers: booking.created, booking.cancelled, and notetaker.media. That covers the full interview lifecycle — scheduled, cancelled, and debriefed.

When a candidate books, the booking.created payload hands you everything your ATS needs in one shot:

{
  "type": "booking.created",
  "data": {
    "grant_id": "<NYLAS_GRANT_ID>",
    "object": {
      "booking_id": "<BOOKING_ID>",
      "booking_info": {
        "event_id": "<EVENT_ID>",
        "start_time": 1719842400,
        "end_time": 1719844500,
        "title": "Interview with Dana Chen",
        "location": "https://meet.google.com/abc-defg-hij"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Your handler creates the interview record, stores the booking_id and event_id for later correlation, and gets out. One operational rule worth following: respond with a 200 immediately and process asynchronously. Nylas retries failed deliveries, but an endpoint that's consistently slow or unreachable eventually gets its notifications dropped — and a silently missed booking is the worst possible failure mode in a hiring pipeline.

When the notetaker.media webhook arrives with state: "available", download the transcript, summary, and action items right away (remember the 60-minute URL expiry), then look up the linked calendar event through the Notetaker API to attach everything to the right candidate record.

One local-dev note: Nylas blocks requests to ngrok URLs, so use VS Code port forwarding or Hookdeck to expose your webhook server while you build.

Where a dedicated agent identity fits

Everything above runs on your interviewers' connected calendars. But the communication side — emailing candidates the booking link, confirming, nudging no-shows — doesn't have to come from a recruiter's personal address. An Agent Account is a real mailbox with its own grant ID that works with the same Messages and Events endpoints, so a recruiting@yourcompany.com identity can own candidate correspondence end to end. The recruiting overview lists the agent-driven variants, including a scheduling agent with its own calendar.

Things that bite in production

  • There's no in-place reschedule. A cancellation fires booking.cancelled and removes the event; the candidate rebooks from scratch. Link ATS records by candidate email so the rebook ties back to the same person.
  • Round-robin counts per Configuration, not globally. An interviewer on two panels can still end up overloaded.
  • Recording consent is a legal question, not a checkbox. The consent message Notetaker shows is informational. Get jurisdiction-specific advice before going live.

Try it on one role first

Don't migrate the whole hiring funnel at once. Pick one role, build the Configuration for that panel, wire the two webhooks, and compare time-to-scheduled against your current process for a couple of weeks. The full tutorial has the complete webhook handlers in Node and Python. What's the slowest step in your hiring loop right now — scheduling, or the debrief?

Top comments (0)