NAV
HTTP

Topics

Teamtailor Partner API

If you have any question or feedback please contact us at support@teamtailor.com

Example use cases of this API:

To set up new clients to use the webhook API, contact support@teamtailor.com for activation and to get the client-specific “provider key”.

Webhooks

When a trigger is executed in Teamtailor, the webhook JSON object is sent to your configurable endpoint.

POST ${BASE_URL}/webhook HTTP/1.1
Authorization: Bearer xxx-provider-key

{
  "partner-event": {
    "id": "f3d7e8e2-da33-4c10-ae5f-0e7f4d46f6d7",
    "webhook-data": {
      "test": "1",
      "threshold": "75"
    },
    "partner-result": {
      "id": "1a6d5a41-f0dd-4226-9d3b-186392bea484",
      "status": "sending"
    },
    "candidate": {
      "id": 54321,
      "first-name": "Juston",
      "last-name": "Becker",
      "email": "applicant100@example.com",
      "phone": "+4670432121",
      "tags": ["developer", "ruby"],
      "department": "Product development",
      "role": "Designer",
      "job": {
        "id": 12345,
        "title": "Full-stack web developer",
        "stage": "After Interview",
        "tags": ["ruby", "javascript"]
      },
      "recruiter": {
        "name": "Edison Kuhn",
        "email": "email1@example.com",
        "phone": "+461234567"
      },
      "locations": [
        {
          "name": "Stockholm",
          "address": "Åsögatan 18, 126 41, Stockholm"
        }
      ],
      "questions": [
        {
          "question": "What are your preferred environments?",
          "answer": ["Ruby on Rails", "Ember.js"]
        }
      ],
      "custom-fields": [
        {
          "has-driver-license": {
              "value": true,
              "type": "boolean"
          },
          "social-security-number":
              "value": "123456-7890",
              "type": "text"
          }
        },
        {
          "question": "How many years relevant work experience do you have?",
          "answer": "10 years"
        },
        {
          "question": "Are you open for working remote?",
          "answer": "yes"
        }
      ]
    },
    "company": {
      "uuid": "vAXspNm0J2Y",
      "name": "Teamtailor",
      "url": "https://career.teamtailor.com",
      "logotype": "https://res.cloudinary.com/teamtailor/image/upload/c_limit,f_auto,h_100,q_auto,w_100,dpr_2.0/v1433344861/b2urpbafegvjzexula0n"
    }
  }
}

HTTP Request

POST ${BASE_URL}/webhook

Webhook JSON object

The JSON object sent to you contains the candidate data, the selected trigger’s “webhook data” and a reference to the partner result object, in case an assessment is requested.

The request is authenticated with the client-specific “provider key” in the Authorization Bearer header.

Attribute Value
id Unique identifier of this event.
webhook-data The picked options from your Webhook config, for example test ID and threshold value.
partner-result The result presented to the customer. Update scores, status etc using the Partner Results resource.
company Company data: uuid, name, url (to career site), logotype (URL to file).
candidate Candidate data.
candidate.job Candidate job data: id, title, stage, tags.
candidate.recruiter Job recruiter data: name, email, phone.
candidate.locations Candidate locations, list with: name, address.
candidate.questions Candidate answers to questions, list with: question, answer. Supported types: Text, Choice (list), Boolean (yes/no), Range (eg, “10 years”), File (url to file, valid for 1 hour)
candidate.custom-fields Candidate custom fields, list with: type, value. Supported types: text, date, boolean, phone, number, email, url

Error handling

We expect your webhook to return a HTTP 2xx status code. Other responses will indicate to us that you didn’t successfully receive the webhook. In this case we will attempt to deliver the webhook every hour for three days or until we get a HTTP 2xx status code. We will notify you by email on the first retry failure as well as every third from there on.

Webhook config

To allow users to pick options for the webhook, that will be included in the webhook sent to you, we will fetch this endpoint each time a new trigger is set up and create a HTML form from the fields.

This could be, for example, a select tag with tests the client can send to candidates.

The JSON to the right is an example of the expected response.

If the config is requested from a “trigger” on a job, we will include the job and stage id’s as parameters, which can be used as context for the form.

Note, if you use the same config with the same set of fields for all clients, you can save a static config on the Partner resource. In that case we won’t fetch this endpoint to get the config.

GET ${BASE_URL}/config?job_id=123&stage_id=456 HTTP/1.1
Authorization: Bearer xxx-provider-key

Expected response

{
  "config": {
    "fields": [
      {
        "id": "type",
        "label": "Test",
        "placeholder": "Select test",
        "type": "select",
        "optgroups": [
          {
            "label": "Logical tests",
            "options": [
              { "id": 1, "label": "Algorithm test" },
              { "id": 2, "label": "Data structure test" },
            ]
          },
          {
            "label": "Programming tests",
            "options": [
              { "id": 3, "label": "Javascript test" },
              { "id": 4, "label": "Ruby test" },
            ]
          }
        ]
      },
      {
        "id": "persona",
        "label": "Persona",
        "placeholder": "Select persona",
        "type": "select",
        "options": [
          { "id": 1, "label": "Senior developer" },
          { "id": 2, "label": "Junior developer" },
        ]
      },
    ]
  }
}

HTTP Request

GET ${BASE_URL}/config

The request is authenticated with the client-specific “provider key” in the Authorization Bearer header.

Expected response

Attribute Type Description
config object Top-level object
fields array List of possible fields (see below)

Field objects

Attribute Type Description
id string Identifier for this field, will be sent in webhook
label string Human readable label
placeholder string Form placeholder
type string Type of form element (see below)
optgroups array Can be used to form a select tag with multiple optgroups (see example)

Supported field types

Field objects follow the HTML form standard in regards to types, possible options, labels and placeholders. For example, disabled may be provided for the “text” type, step, min and max may be provided for the “number” type and an options array with id/label may be provided for the “select” type.

All of the supported field types:

File uploads

When using the file type, we upload the files to a private folder on S3, and send a signed URL to the file in the webhook. This URL is valid for 24 hours, so make sure to download the file when the webhook is sent to you.

Webhook signatures

To validate authenticity of webhooks sent by Teamtailor we include a Teamtailor-Signature header in each request. The header contains a HMAC and allows you to validate that the webhook was actually sent by Teamtailor. Webhooks signatures are optional and if you’d like to use it, please contact us on partner@teamtailor.com we’ll provide you with the secret key needed.

Signature structure

The structure of Teamtailor-Signature is a timestamp (to prevent replay attacks) followed by a comma and two or more schemes separated by commans. The current only valid signature scheme is v1 and the latest scheme should always be used to prevent downgrading attacks.

# Example signature
Teamtailor-Signature: t=1539756759,
  v1=2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae,
  v0=fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9

Checking signatures

To validate a signature you may first check that the timestamp is in valid range (eg five minutes). This range is, however, up to you.

After checking the timestamp you can verify the hash by computing it yourself and compare it to the lastest hash included in the request, vX. If it match, Teamtailor sent the webhook.

# Computing the hash
hash = sha256(timestamp + "." + payload, secret_key)

Example implementation (Node)

// Bundled with Node
const crypto = require('crypto');

// External dependencies
const express = require('express');
const bodyParser = require('body-parser');

// Webhook secret as environment variable
const SECRET = process.env.WEBHOOK_SECRET;

app.post('/webhook', bodyParser.raw({type: 'application/json'}), (req, res) => {
  const signaturePattern = /^t=(\d+),v\d=(\w+),.+$/;
  const signature = req.headers['teamtailor-signature'];
  const [_, timestamp, cHmac] = signaturePattern.exec(signature);
  const payload = `${timestamp}.${payload}`;
  const hmac = crypto.createHmac('sha256', SECRET)
    .update(payload, 'utf-8')
    .digest('hex');
  if (cHmac === hmac) {
    // Signature check passed.
    // If you want to prevent replay attacks, check timestamp as well.
    return res.status(200).send();
  }
  return res.status(401).send();
})

Changelog

2019-04-02

Added company.uuid, candidate.tags, and job.tags fields to the webhook.

2018-08-28

First release of this documentation.

API Resources

Introduction

The resources in our Partner API is accessible using the JSON API Specification.

Authentication

GET https://api.teamtailor.com/partner/v1/partner-results HTTP/1.1
Authorization: Token abc123abc123

Authenticate your account by including your secret API key in the request. Contact support to get or reset your API key.

Autentication is performed by passing the api key in the Authorization header.

Versioning

GET https://api.teamtailor.com/partner/v1/partner-results HTTP/1.1
X-Api-Version : 20180828

When we make backwards-incompatible changes to the API, we release new, dated versions.

To set the API version on a specific request, send a X-Api-Version header. See the API changelog to see current and old versions.

Successful API requests will have the used API version in the response header X-Api-Version

Partners

This is the object representing your Partner account. For most use-cases this object won’t be used, but you can change your BASE_URL by updating this object. You can also save a static “webook-config” that will be used instead of the /config endpoint.

Partner object

{
  "data": {
    "id": "99",
    "type": "partners",
    "links": {
      "self": "https://api.teamtailor.com/partner/v1/partners/99"
    },
    "attributes": {
      "name": "Pied Piper",
      "base-url": "https://piedpiper.com/teamtailor",
      "webhook-config": {
        "config": {
          "fields": [
            {
              "id": "type",
              "label": "Test",
              "placeholder": "Select test",
              "type": "select",
              "options": [
              { "id": 1, "label": "Sales test" },
              { "id": 2, "label": "Programming test" },
              { "id": 3, "label": "Math exam" }
              ]
            },
            {
              "id": "threshold",
              "label": "Threshold",
              "placeholder": "Minimum score to pass",
              "type": "number",
              "step": 5,
              "min": 0,
              "max": 100
            }
          ]
        }
      }
    }
  }
}

Attributes

Attribute Type Description
name string Immutable Partner name
base-url string Base URL for receiving webhooks
webhook-config object Static webhook config object (optional).

Get partner

GET https://api.teamtailor.com/partner/v1/partners/99 HTTP/1.1
Authorization: Token abc123abc123
X-Api-Version: 20180828

Example response

{
  "data": {
    "id": "99",
    "type": "partners",
    "links": {
      "self": "https://api.teamtailor.com/partner/v1/partners/99"
    },
    "attributes": {
      "name": "Pied Piper",
      "base-url": "https://piedpiper.com",
      "webhook-config": {
        "config": {
          "fields": [
            {
              "id": "type",
              "label": "Test",
              "placeholder": "Select test",
              "type": "select",
              "options": [
                { "id": 1, "label": "Sales test" },
                { "id": 2, "label": "Programming test" },
                { "id": 3, "label": "Math exam" }
              ]
            },
            {
              "id": "threshold",
              "label": "Threshold",
              "placeholder": "Minimum score to pass",
              "type": "number",
              "step": 5,
              "min": 0,
              "max": 100
            }
          ]
        }
      }
    }
  }
}

Update partner

PUT https://api.teamtailor.com/partner/v1/partners/99 HTTP/1.1
Authorization: Token abc123abc123
X-Api-Version: 20180828
Content-Type: application/vnd.api+json

{
  "data": {
    "id": 99,
    "type":"partners",
    "attributes":{
      "base-url": "https://piedpiper.com",
      "webhook-config": {
        "config": {
          "fields": [
            {
              "id": "type",
              "label": "Test",
              "placeholder": "Select test",
              "type": "select",
              "options": [
                { "id": 1, "label": "Sales test" },
                { "id": 2, "label": "Programming test" },
                { "id": 3, "label": "Math exam" }
              ]
            }
          ]
        }
      }
    }
  }
}

Example response

{
  "data": {
    "id": "99",
    "type": "partners",
    "links": {
      "self": "https://api.teamtailor.com/partner/v1/partners/99"
    },
    "attributes": {
      "name": "Pied Piper",
      "base-url": "https://piedpiper.com",
      "webhook-config": {
        "config": {
          "fields": [
            {
              "id": "type",
              "label": "Test",
              "placeholder": "Select test",
              "type": "select",
              "options": [
                { "id": 1, "label": "Sales test" },
                { "id": 2, "label": "Programming test" },
                { "id": 3, "label": "Math exam" }
              ]
            },
            {
              "id": "threshold",
              "label": "Threshold",
              "placeholder": "Minimum score to pass",
              "type": "number",
              "step": 5,
              "min": 0,
              "max": 100
            }
          ]
        }
      }
    }
  }
}

Partner Results

This is the object representing a result from a test or similar, displayed on the candidate profile.

Partner result object

{
  "data": {
    "id": "3230d614-a33b-4a25-ac9c-4ec107e60f2e",
    "type": "partner-results",
    "links": {
      "self": "https://api.teamtailor.com/partner/v1/partner-results/3230d614-a33b-4a25-ac9c-4ec107e60f2e"
    },
    "attributes": {
      "assessment": {
        "score": 82,
        "grade": "excelled",
        "duration": 1934
      },
      "details": {
        "rating": "10",
        "awesomeness": "confirmed"
      },
      "status": "sent",
      "summary": "High five",
      "url": "apple.com",
      "candidate-id": 333,
      "attachments": [
        {
          "url": "https://google.com/robots.txt",
          "description": "Test results"
        }
      ]
    }
  }
}

Attributes

Attribute Type Description
assessment object Assessment object.
details object Details object. May be any valid JSON object at most 2 levels deep. The data is displayed to the customer.
status string May be “sending”, “sent”, “pending”, “completed” or “failed”.
summary string Summary text.
url string URL for viewing a report on your website.
candidate-id string Immutable UUID identifier for candidate.
attachments list List of attachment objects containing keys: “url” and “description”.

Assessment object

Attribute Type Description
score integer Must be between 0 and 100.
grade string May be “failed”, “passed” or “excelled”.
duration integer Duration of test in seconds

Update a result

PUT https://api.teamtailor.com/partner/v1/partner-results/3230d614-a33b-4a25-ac9c-4ec107e60f2e HTTP/1.1
Authorization: Bearer abc123abc123
X-Api-Version: 20180828
Content-Type: application/vnd.api+json

{
  "data":{
    "type": "partner-results",
    "id": "3230d614-a33b-4a25-ac9c-4ec107e60f2e",
    "attributes":{
      "status": "completed",
      "summary": "The candidate passed the test with excellent results",
      "assessment": {
        "score": 82,
        "grade": "excelled",
        "duration": "0:32:14"
      },
      "details": {
        "rating": "10",
        "awesomeness": "confirmed"
      }
    }
  }
}

Example response

{
  "data": {
    "id": "3230d614-a33b-4a25-ac9c-4ec107e60f2e",
    "type": "partner-results",
    "links": {
      "self": "https://api.teamtailor.localhost/partner/v1/partner-results/3230d614-a33b-4a25-ac9c-4ec107e60f2e"
    },
    "attributes": {
      "assessment": {
        "score": 82,
        "grade": "excelled",
        "duration": 1934
      },
      "details": {
        "rating": "10",
        "awesomeness": "confirmed"
      },
      "status": "completed",
      "summary": "The candidate passed the test with excellent results",
      "url": "http://www.example.com/test/1234",
      "candidate-id": 102
    }
  }
}

Update a result by using the ID from the Webhook object.

Create a new result

POST https://api.teamtailor.com/partner/v1/partner-results HTTP/1.1
Authorization: Bearer abc123abc123
X-Api-Version: 20180828

{
  "data":{
    "type": "partner-results",
    "attributes":{
      "status": "completed",
      "summary": "The candidate passed the test with excellent results",
      "assessment": {
        "score": 82,
        "grade": "excelled",
        "duration": "0:32:14"
      },
      "details": {
        "rating": "10",
        "awesomeness": "confirmed"
      }
    }
  }
}

Example response

{
  "data": {
    "id": "3230d614-a33b-4a25-ac9c-4ec107e60f2e",
    "type": "partner-results",
    "links": {
      "self": "https://api.teamtailor.localhost/partner/v1/partner-results/3230d614-a33b-4a25-ac9c-4ec107e60f2e"
    },
    "attributes": {
      "assessment": {
        "score": 82,
        "grade": "excelled",
        "duration": 1934
      },
      "details": {
        "rating": "10",
        "awesomeness": "confirmed"
      },
      "status": "completed",
      "summary": "The candidate passed the test with excellent results",
      "url": "http://www.example.com/test/1234",
      "candidate-id": 102
    }
  }
}

Delete a result

DELETE https://api.teamtailor.com/partner/v1/partner-results/3230d614-a33b-4a25-ac9c-4ec107e60f2e HTTP/1.1
Authorization: Bearer abc123abc123
X-Api-Version: 20180828