Scheduling
Telling us when the candidate is expected.
curl -X POST https://hiring-api.experthire.cloud/v1/assessments/$ASSESSMENT_ID/schedule \
-H "Authorization: Bearer $EH_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"start_at": 1767225600, "time_zone": "Asia/Kolkata"}'
Still a placeholder: $ASSESSMENT_ID, $EH_SECRET_KEY. Add them under Your values above.
{
"object": "assessment_schedule",
"assessment_id": "3b8e1d02-5c77-4c2a-8a41-9b2f7e6d4c10",
"status": "scheduled",
"start_at": 1767225600,
"end_at": 1767227400,
"rescheduled": false,
"reschedule_count": 0,
"livemode": false
}
We record the start and derive the end from the assessment's length, including the intro
buffer where one applies. time_zone is used in the candidate's reminders.
A new assessment is scheduled with no time set. The first time it gets is not a
reschedule, whether you post it here or the candidate books it on the booking page.
Calling this again after a time is set reschedules it.
Setting the time emits interview.scheduled, and each later change emits
interview.rescheduled. Both fire whether the time came from this endpoint or from the
candidate picking a slot on the booking page.
What we email the candidate
Three things, all from your own sending domain once one is verified, and all carrying your logo and brand colour. Roles created through the API send as your company, not as a person.
| When | Governed by | |
|---|---|---|
| Invite | On create, only if you pass send_invite | send_invite on the create call |
| Booking confirmation | When the candidate picks a time on the booking page, or when you set it with this endpoint | Always sent from the booking page. From this endpoint, only if you passed send_invite on create |
| Reminder | Once, when the assessment is under 24 hours away | Nothing. Always sent |
None of these go out for a human_interview. We send
nothing for one, and it cannot be booked on our booking page.
The booking confirmation carries an .ics, so the assessment lands on the candidate's
calendar with the join link inside the entry. A reschedule sends an updated one. The
reminder uses time_zone, so set it to the candidate's zone rather than yours.
The Email candidates by default setting in your dashboard governs only the invite
the recruiter app sends when an interview is created. It does not stop booking
confirmations or reminders, and it has no effect on this API at all: send_invite is
the only control here.
Reminders only fire for an assessment with a booked time. One that nobody scheduled has
nothing to remind against, and is swept as a no-show about seven days after creation.
The sweep emits interview.cancelled and emails nobody: the candidate is not told they
missed it.
The booking page, and why there is no slots endpoint
We host a candidate-facing booking page, but we do not publish availability. Those are different things, and the distinction decides what you build.
There is no endpoint that offers slots. But there is a candidate-facing booking page, hosted by us on your branded domain:
https://<your-domain>/schedule-call/{assessment_id}
The id is the one POST /v1/assessments returned, and the page is public: the id alone
identifies the assessment, with no token to mint. The candidate picks a time, and gets the
confirmation and calendar invite described above.
So you have two candidate journeys, and should pick one rather than sending both:
| Launch link | Booking page | |
|---|---|---|
| URL | POST /v1/assessments/{id}/launch-link | /schedule-call/{id} on your domain |
| Candidate | Joins immediately | Picks a time, joins later |
| Lifetime | Single use, 7 days at most | Re-openable |
| Calendar invite | No | Yes |
A launch link does not redirect to the booking page. It opens the assessment.
There is deliberately no slots endpoint behind any of this. We do not model availability, and we check neither capacity, recruiter calendars nor conflicts, so offering slots would imply a guarantee that does not exist. The booking page lets the candidate choose a time; it does not promise anyone is free at it.
If you schedule from your own system instead, pick the time there and post the result to
/schedule.
If you would rather not schedule at all
You do not have to. An assessment with a launch link works whenever the candidate opens it. Scheduling exists for the case where you want the time on record and reflected in the customer's dashboard and the candidate's reminders.
Rescheduling
Post to the same endpoint again with a new start_at. There is no separate reschedule
call. It only counts as a reschedule once a time is already set, by you or by the
candidate on the booking page. The response tells you it happened:
{
"object": "assessment_schedule",
"status": "scheduled",
"start_at": 1748955600,
"end_at": 1748957400,
"rescheduled": true,
"reschedule_count": 1
}
Cancelling
POST /v1/assessments/{id}/cancel withdraws it. Cancelling one that is already cancelled
returns it unchanged, so retrying is safe.
The credit comes back only if the assessment was never taken, meaning it is still
pending or scheduled and has no outcome. Once a candidate has attended, the work is
done and there is nothing to return.
Resume screens
A resume_screen has no call to attend, so scheduling one returns
unsupported_operation. Cancelling one works normally.