Indeed Interview API guide

Schedule, manage, and get information about virtual interviews with job candidates.

📘

Note:

By using this API and its documentation and building an integration, you agree to the Additional API Terms and Guidelines.

Before you start

📘

Note:

Before you can develop against this API, you must contact [email protected] to request access.

To understand Indeed’s requirements to use the Interview API, read the Additional API Terms and Guidelines.

Guidelines

As a consumer of the Interview API, you agree to:

  • Place a button in your user interface that enables your clients, the employers, to create an interview with Indeed Platform.

    The button must meet the specifications that Indeed provides.

  • Describe to a job seeker which data you collect from and about them, and how you share that data with Indeed when they are scheduled for an interview.

  • Honor any request from a job seeker for their data in connection with any API.

  • Provide applicant tracking system (ATS) name and interviewee email address through this API.

  • Provide the employer name when that data is available to you.

Authentication

Use the authorization code flow (3-legged OAuth) to get a client ID and secret, an authorization code, and an access token.

You exchange the client ID for an authorization code with the interviews.schedule, employer_access, and offline_access scopes. To enable the user to select an Indeed employer that is associated with their Indeed account, specify the prompt=select_employer parameter in the authorization code request.

After you get an authorization code, exchange it and the client ID and secret for an access token, which lasts one hour, a refresh token that lasts 60 days, and an ID token that contains user information. The employer is returned as an advertiser ID in the ID token.

Use the access token for authentication when you call the Interview API.

To call the API, POST the request to the following endpoint:

POST https://apis.indeed.com/graphql

📘

Note:

Use the POST method for all queries and mutations. The API does not support the GET method.

In the POST request body, include the query, an optional operation name, and variable inputs:

{
  "query": "...",
  "operationName": "...",
  "variables": {
    "myVariable": "someValue",
    ...
  }
}

Interview API overview

📘

Note:

For information about how to authenticate and call the API, see Before you start.

Use the Interview API to schedule, update, get information about, or cancel a virtual event.

An event can include one, or no, interviewee, and from 1 to 49 interviewers. You can add an interviewee and interviewers to the event after you schedule it.

If the request succeeds, the API confirms that the event was scheduled and returns information about the event, including the unique interview ID. The API automatically adds you as an interviewer to the event, notifies each interviewer that they have been added to the event, adds calendar items to each interviewer's calendar, and sends the interviewer link to the interviewers. The applicant tracking system (ATS) handles communications with the interviewee.

A few minutes before the event begins, Indeed emails the interviewee to remind them of the event with a link to the event. When the event begins, each interviewer must log in with their Indeed account. Any interviewer without an account must create one. Interviewees do not need to create accounts.

An interviewer for an event can use the unique interview ID for an event to get details about, update, or cancel the event. You can make only one type of update at a time in an update request for an event. You can reschedule it, add interviewers to it, add an interviewee to it, change its title, or change its associated time zone. You can only add an interviewee to an event that does not already have an interviewee.

You can also:

  • List virtual interview events, by IDs
  • List events within a data range and optionally sorted by start or end time, status, and media type

Schedule and manage events

Use the Interview API to schedule, update, or cancel a virtual event.

Schedule an event

createVirtualInterviewEvent(
  input: CreateVirtualInterviewEventInput!
): CreateVirtualInterviewEventPayload

To schedule a virtual event, call the createVirtualInterviewEvent mutation with the CreateVirtualInterviewEventInput input object. All fields are required except interviewee, languageCode, and countryCode.

An event can include 1, or no, interviewee, and from 1 to 49 interviewers.

mutation CreateEvent {
  createVirtualInterviewEvent(input: {
    startTime: "2022-08-18T22:30:00+00:00"
    endTime: "2022-08-18T23:30:00+00:00"
    title: "Interview with Candidate"
    timezone: "America/Los_Angeles"
    interviewers: [{
      email: "[email protected]"
    }, {
      email: "[email protected]"
    }]
    interviewee: {
      name: "Candidate",
      email: "[email protected]"
    }
    requestMetadata: {
      atsName: "ExampleATS",
      employerName: "Test Company"
    }
    languageCode: "fr"
    countryCode: "CA"
  }) {
    event {
      id
      countryCode
      languageCode
      interviewerLobbyUrl
      intervieweesConnection {
        interviewees {
          intervieweeLobbyUrl
          name
          email
        }
      }
      interviewersConnection {
        pageInfo {
          endCursor
        }
        interviewers {
          email
        }
      }
    }
  }
}

The mutation returns the CreateVirtualInterviewEventPayload return type.

If the request succeeds, the API confirms that the event was scheduled and returns information about the event, including the unique interview ID. The API automatically adds you as an interviewer to the event, notifies each interviewer that they have been added to the event, adds calendar items to each interviewer's calendar, and sends the interviewer link to the interviewers. The applicant tracking system (ATS) handles communications with the interviewee.

A few minutes before the event begins, Indeed emails the interviewee to remind them of the event with a link to the event. When the event begins, each interviewer must log in with their Indeed account. Any interviewer without an account must create one. Interviewees do not need to create accounts.

If a validation error occurs, the request fails.

📘

Validation error:

A validation error occurs when:

  • The total number of interviewers exceeds 49.
  • The interview duration is greater than 24 hours.

Reschedule an event

updateVirtualInterviewEvent(
  input: UpdateVirtualInterviewEventInput!
): UpdateVirtualInterviewEventPayload

To update the start date and time and end date and time for the event, call the updateVirtualInterviewEvent mutation with the UpdateVirtualInterviewEventInput input object. In that input object, specify the reschedule field with the RescheduleVirtualInterviewEventInput input object.

mutation RescheduleEvent {
  updateVirtualInterviewEvent(input: {
    reschedule: {
      id: "aXJpOi8vYXBpcy5pbmRlZWQuY29tL1ZpcnR1YWxJbnRlcnZpZXdFdmVudC8zZjM3MmEzNy05NTI5LTQ0NmItYmQ5OC01ZGJjOGMwNTdjODQ="
      startTime: "2022-08-19T22:30:00+00:00"
      endTime: "2022-08-19T23:30:00+00:00"
    }
  }) {
    event {
      id
      status
      title
      startTime
      endTime
      timezone
      languageCode
      countryCode
      interviewerLobbyUrl
      interviewersConnection {
        interviewers {
          name
          email
        }
      }
      intervieweesConnection {
        interviewees {
          intervieweeLobbyUrl
          name
          email
        }
      }
    }
  }
}

The mutation returns the UpdateVirtualInterviewEventPayload return type, which includes the updated VirtualInterviewEvent return type.

  • If the request succeeds, the API confirms that the event was rescheduled successfully and returns information about the event, including the unique interview ID.

  • If a validation error occurs, the request fails.

    📘

    Validation error:

    A validation error occurs when the event duration is greater than 24 hours.

Add interviewers to an event

updateVirtualInterviewEvent(
  input: UpdateVirtualInterviewEventInput!
): UpdateVirtualInterviewEventPayload

To add interviewers to an event, call the updateVirtualInterviewEvent mutation with the UpdateVirtualInterviewEventInput input object. In that input object, specify the addInterviewers field with the UpdateVirtualInterviewEventInterviewersInput input object.

mutation AddInterviewersToEvent {
  updateVirtualInterviewEvent(input: {
    addInterviewers: {
      id: "c0cbfcf3-961a-4b6f-a199-e4043f4016cf"
      interviewers: [{
          email: "[email protected]"
        },
        {
          email: "[email protected]"
        },
        {
          email: "[email protected]"
        }
      ]
    }
  }) {
    event {
      id
      status
      title
      startTime
      endTime
      timezone
      languageCode
      countryCode
      interviewerLobbyUrl
      interviewersConnection {
        interviewers {
          name
          email
        }
      }
      intervieweesConnection {
        interviewees {
          intervieweeLobbyUrl
          name
          email
        }
      }
    }
  }
}

The mutation returns the UpdateVirtualInterviewEventPayload return type, which includes the updated VirtualInterviewEvent return type.

  • If the request succeeds, the API confirms that the interviewers for the event were added successfully and returns information about the event, including the unique interview ID.

  • If a validation error occurs, the request fails.

    📘

    Validation error:

    A validation error occurs when the total number of interviewers exceeds 49.

Add an interviewee to an event

updateVirtualInterviewEvent(
  input: UpdateVirtualInterviewEventInput!
): UpdateVirtualInterviewEventPayload

To add an interviewee to an event, call the updateVirtualInterviewEvent mutation with the UpdateVirtualInterviewEventInput input object. In that input object, specify the addInterviewee field with the AddVirtualInterviewEventIntervieweeInput input object.

📘

Notes:

  • You can add only one interviewee to an event, and you cannot change the interviewee for an event.
  • If you need to change the interviewee for an event, cancel the event and schedule one with the correct interviewee.
mutation AddIntervieweeToEvent {
  updateVirtualInterviewEvent(input: {
    addInterviewee: {
      id: "c0cbfcf3-961a-4b6f-a199-e4043f4016cf"
      interviewee: {
        name: "intervieweeName"
        email: "[email protected]"
      }
    }
  }) {
    event {
      id
      status
      title
      startTime
      endTime
      timezone
      languageCode
      countryCode
      interviewerLobbyUrl
      interviewersConnection {
        interviewers {
          name
          email
        }
      }
      intervieweesConnection {
        interviewees {
          intervieweeLobbyUrl
          name
          email
        }
      }
    }
  }
}

The mutation returns the UpdateVirtualInterviewEventPayload return type, which includes the updated VirtualInterviewEvent return type.

  • If the request succeeds, the API confirms that the interviewee for the event was added successfully and returns information about the event, including the unique interview ID.
  • If a validation error occurs, the request fails.

Change the title for an event

updateVirtualInterviewEvent(
  input: UpdateVirtualInterviewEventInput!
): UpdateVirtualInterviewEventPayload

To change the title for an event, call the updateVirtualInterviewEvent mutation with the UpdateVirtualInterviewEventInput input object. In that input object, specify the setTitle field with the UpdateVirtualInterviewEventTitleInput input object.

mutation SetTitleOfEvent {
  updateVirtualInterviewEvent(input: {
    setTitle: {
      id: "c0cbfcf3-961a-4b6f-a199-e4043f4016cf"
      title: "Interview with Candidate"
    }
  }) {
    event {
      id
      status
      title
      startTime
      endTime
      timezone
      languageCode
      countryCode
      interviewerLobbyUrl
      interviewersConnection {
        interviewers {
          name
          email
        }
      }
      intervieweesConnection {
        interviewees {
          intervieweeLobbyUrl
          name
          email
        }
      }
    }
  }
}

The mutation returns the UpdateVirtualInterviewEventPayload return type, which includes the updated VirtualInterviewEvent return type.

  • If the request succeeds, the API confirms that the title for the event was changed successfully and returns information about the event, including the unique interview ID.
  • If a validation error occurs, the request fails.

Change the time zone for an event

updateVirtualInterviewEvent(
  input: UpdateVirtualInterviewEventInput!
): UpdateVirtualInterviewEventPayload

To change the time zone for an event, call the updateVirtualInterviewEvent mutation with the UpdateVirtualInterviewEventInput input object. In that input object, specify the setTimezone field with the UpdateVirtualInterviewEventTimezoneInput input object.

mutation SetTimezoneOfEvent {
  updateVirtualInterviewEvent(input: {
    setTimezone: {
      id: "c0cbfcf3-961a-4b6f-a199-e4043f4016cf"
      timezone: "America/Los_Angeles"
    }
  }) {
    event {
      id
      status
      title
      startTime
      endTime
      timezone
      languageCode
      countryCode
      interviewerLobbyUrl
      interviewersConnection {
        interviewers {
          name
          email
        }
      }
      intervieweesConnection {
        interviewees {
          intervieweeLobbyUrl
          name
          email
        }
      }
    }
  }
}

The mutation returns the UpdateVirtualInterviewEventPayload return type, which includes the updated VirtualInterviewEvent return type.

  • If the request succeeds, the API confirms that the time zone for the event was changed successfully and returns information about the event, including the unique interview ID.
  • If a validation error occurs, the request fails.

Cancel an event

cancelVirtualInterviewEvent(
  input: CancelVirtualInterviewEventInput!
): CancelVirtualInterviewEventPayload

To cancel an event, call the cancelVirtualInterviewEvent mutation with the CancelVirtualInterviewEventInput input object:

mutation CancelEvent {
  cancelVirtualInterviewEvent(input: {
    id: "c0cbfcf3-961a-4b6f-a199-e4043f4016cf"
  }) {
    event {
      id
      status
      title
      startTime
      endTime
      timezone
      languageCode
      countryCode
      interviewerLobbyUrl
      interviewersConnection {
        interviewers {
          name
          email
        }
      }
      intervieweesConnection {
        interviewees {
          intervieweeLobbyUrl
          name
          email
        }
      }
    }
  }
}

The mutation returns the CancelVirtualInterviewEventPayload return type, which includes the updated VirtualInterviewEvent return type.

  • If the request succeeds, the API confirms that the event was canceled successfully and returns information about the event.
  • If a validation error occurs, the request fails.

Get information about events

You can show details for one or more events, by ID, or list events within a date range.

List virtual interview events, by IDs

virtualInterviewEvents(
  input: VirtualInterviewEventsInput!
): VirtualInterviewEventsPayload

To list virtual interview events, by IDs, call the virtualInterviewEvents query with the VirtualInterviewEventsInput input object:

query GetEvent {
  virtualInterviewEvents(input: {
    ids: [
      "aXJpOi8vYXBpcy5pbmRlZWQuY29tL1ZpcnR1YWxJbnRlcnZpZXdFdmVudC9jMGNiZmNmMy05NjFhLTRiNmYtYTE5OS1lNDA0M2Y0MDE2Y2Y=",
      "aXJpOi8vYXBpcy5pbmRlZWQuY29tL1ZpcnR1YWxJbnRlcnZpZXdFdmVudC8zZjM3MmEzNy05NTI5LTQ0NmItYmQ5OC01ZGJjOGMwNTdjODQ="
    ]
  }) {
    events {
      id
      interviewerLobbyUrl
      intervieweesConnection {
        interviewees {
          intervieweeLobbyUrl
          name
          email
          interviewRecordsConnection {
            records {
              id
              recordingUrl
              interviewOutcomesConnection {
                outcomes {
                  interviewer {
                    id
                    email
                    name
                  }
                  decision {
                    value
                    noteText
                  }
                }
              }
            }
          }
        }
      }
      interviewersConnection {
        pageInfo {
          endCursor
        }
        interviewers {
          email
        }
      }
    }
  }
}

The query returns the VirtualInterviewEventsPayload return type, which includes the updated VirtualInterviewEvent return type, which lists events.

List events within a date range

findVirtualInterviewEvents(
  first: Int = 10,
  after: String,
  input: FindVirtualInterviewEventsInput!
): VirtualInterviewEventsConnection

To list events within a date range, call the findVirtualInterviewEvents query with the FindVirtualInterviewEventsInput input object.

You can use the first and after fields to specify:

  • first. The number of events to list.
  • after. The date and time after which to list events.

In the FindVirtualInterviewEventsInput input object, you can specify these optional filters:

  • Start time of the time range of the event.
  • End time of the time range of the event.
  • Sort options.
query FindEvents {
  findVirtualInterviewEvents(
    first: 50,
    after: "ZmIyNDUxZjAtYjBjMy00NTljLTk4MGItNTVlMThhNWNlOWU0fDQ"
    input: {
      startTime: {
        after: "2022-06-29T22:00:00+00:00"
      }
    }
  ) {
    events {
      id
      title
      startTime
      endTime
      interviewersConnection {
        interviewers {
          email
        }
      }
    }
    pageInfo {
      startCursor
      endCursor
      hasNextPage
      hasPreviousPage
    }
    totalCount
  }
}

The query returns the VirtualInterviewEventsConnection return type with a paginated list of events that are scheduled after a specified date.

  • If the request succeeds, the API returns pagination information for the events within the date range.
  • If a validation error occurs, the request fails.

Notes on accessing event recordings

When you conduct an interview on Indeed's platform, you can record it. When an interview concludes, Indeed sends an email to the interviewers with a link to the recording. You can also access this link through the API, in the recordingUrl field in the VirtualInterviewRecord return type.

Each VirtualInterviewRecord return type corresponds to an individual interview. If an interviewee participates in multiple interviews in separate sessions in a single event, a recording exists for each interview.

If there are multiple videos from a single interview, that is, recordings are repeatedly enabled and disabled, those videos are concatenated.

The recording appears in the UI on our website. Only interviewers who participated in the interview can view the recording even if the link is shared. Recordings expire after 90 days, after which the link shows an error page.

Sometimes a delay occurs between the end of an interview and when the recording becomes available to view. If a recording is not available after 24 hours, contact Indeed to investigate the issue.

The recordingUrl field value is null if no recording is available for an interview record, either because it wasn't recorded or because it hasn't finished processing. It is also null if an error occurs in processing the video. If a recording is available, the field contains the URL for the webpage where it can be viewed.

Troubleshoot errors

Troubleshoot common errors

When a request fails, the data field is null, and the errors field contains information about what went wrong.

The following table describes the common error types:

Error Description and common causes
BAD_USER_INPUT

The value of an input parameter is not valid or the server cannot process your request based on the provided input. See consult the error message for details.

INTERNAL_SERVER_ERROR

The server encountered an unexpected failure, error, or exception and did not provide a response. This can happen for various reasons and is closely monitored by Indeed. Try your request again.

UNAUTHENTICATED

The request did not include sufficient authentication credentials. For details on how to provide authentication credentials, see Authorization.

FORBIDDEN

Valid authentication credentials are present but insufficient to perform the associated query or mutation. For details, see the error message.

📘 Note:

This error occurs when you attempt to access an event that does not exist.

Example – Invalid request

In this request, the after pagination cursor incorrectly contains special characters.

query {
  findVirtualInterviewEvents(
    input: {
      startTime: {
        after: "2022-07-19T23:21:27+00:00"
        before: "2022-07-19T23:21:30+00:00"
      }
      endTime: {
        after: "2022-07-19T23:21:27+00:00"
        before: "2022-07-19T23:21:30+00:00"
      }
    }, after: "1˙∆") {
    events {
      id
    }
  }
}

Example – Error response

In an error response, data is null. Information about what went wrong appears in the errors section, with details in message.

{
  "errors": [{
    "message": "Encountered issue parsing cursor '1˙∆'.",
    "locations": [{
      "line": 3,
      "column": 3
    }],
    "path": [
      "findVirtualInterviewEvents"
    ],
    "extensions": {
      "code": "BAD_USER_INPUT",
      "logLevel": "INFO"
    }
  }],
  "data": {
    "findVirtualInterviewEvents": null
  }
}

📘

Note:

When using the Get query type and some IDs encounter errors, they appear as null in "data" along with any successes.

Troubleshoot authorization errors

Authorization endpoints, such as https://apis.indeed.com/oauth/v2/tokens, return errors in the format that the OAuth 2.0 authorization framework requires. See RFC6749.

For example:

{
  "error_description": "Invalid grant",
  "error": "invalid_grant"
}
Error Description

invalid_grant

Your client ID, client secret, authorization code, or refresh token is incorrect.

The error_description field contains a generic Invalid grant message. To resolve this error, review invalid_grant errors – Causes and resolutions.

invalid_request

A request parameter has an issue.

The error_description field describes the issue. To resolve this error, review invalid_request errors – Causes and resolutions.

unsupported_grant_type

The requested grant type is not supported.

The requested grant_type must be one of the following values:

invalid_request errors – Causes and resolutions

To resolve an invalid_request error, review the following causes and resolutions:

Cause Resolution
Incorrect or missing parameter

A required parameter is missing or has an invalid value.

Include or correct the parameter.

Misplaced query string parameters

The https://apis.indeed.com/oauth/v2/tokens request includes query string parameters in the request URL.

Include query string parameters in the HTTP request body, by using the application/x-www-form-urlencoded format.

Incorrect employer parameter value

The issue can occur for one of these reasons:

  • The app's account, which uses client credentials flow (2-legged OAuth), or the user, who uses authorization code flow (3-legged OAuth), does not have permission to access the employer that the employer parameter identifies.

  • The employer parameter did not contain a valid employer ID. The employer parameter accepts different employer ID values than the legacy advertiserId parameter accepts.

To list valid employer values:

  • For 2-legged OAuth, call the appinfo endpoint. See Call an Indeed API.

  • For 3-legged OAuth, call the userinfo endpoint. See userinfo endpoint.

  • If you have a master account, call this Sponsored Jobs API endpoint:

    GET /v1/subaccounts

Then, update the value of the employer parameter.

invalid_grant errors – Causes and resolutions

To resolve an invalid_grant error, review the following causes and resolutions:

Cause Resolution
Incorrect client ID or secret

You copy a credential incorrectly from Manage app credentials.

Verify your client ID and secret.

Incorrect client secret

You add a secret and delete the original secret for your client ID but do not update all your credential stores.

Verify that your credential stores contain the latest client secret.

Disabled client credentials grant type

You use the client credentials flow (2-legged OAuth) and the client credentials grant type is not enabled.

On Manage app credentials, select Client credentials in Allowed grant types.

Disabled authorization code grant type

You use the authorization code flow (3-legged OAuth) and the authorization code grant type is not enabled.

On Manage app credentials, select Authorization code in Allowed grant types.

Mismatched redirect_uri parameter values

You use the authorization code flow (3-legged OAuth) and these values do not match:

  • the redirect_uri parameter value that you sent to https://apis.indeed.com/oauth/v2/tokens
  • the redirect_uri parameter value that you sent to https://secure.indeed.com/oauth/v2/authorize

Ensure that the two redirect_uri parameter values match.

Expired or already-used authorization code

You use the authorization code flow (3-legged OAuth) and you used an expired or already-used authorization code. You can use an authorization code only one time.

To renew access tokens without reauthorization, request the offline_access scope and store the refresh token with the first access token.

Refresh token is not valid

You use the authorization code flow (3-legged OAuth) and the refresh token is not valid. Refresh tokens expire 60 days after last usage or after issue if never used.

This issue can occur for one of these reasons:

  • The user revoked authorization from your app.

  • Your app requested sequential authorizations from the same user but the original refresh tokens for this user are not valid. After each successful sequential authorization, you must update the refresh token that your app stores.

  • Because the refresh token was not used recently, it expired.

Ask the user to request another refresh token through the authorization code flow (3-legged OAuth).

The authorization code or refresh token is not valid for your app

You use the authorization code flow (3-legged OAuth) and the authorization code or refresh token is valid but it was issued to a different app.

Use the same client ID and secret through all stages of the authorization process.

See also