API Access

TutorCruncher has a comprehensive API allowing you to perform any action available in the standard user interface programmatically.

If you wish to have access to your API, please contact us at support@tutorcruncher.com.

With API access activated visit TutorCruncher setup, from there you can generate an API token and get a link to the browsable API.

Have you tried TutorCruncher Socket Frontend?

Socket Frontend is a quick and easy way of displaying tutor's profiles, as well as allowing clients to select tutors and make enquiries, all through your website. If you feel like you want to do more with Socket, then read on, otherwise you can go to our docs on Socket to set it up.

Getting Started

There are two ways of accessing TutorCruncher's API, either straight to the API, or using TutorCruncher Socket Server.

At the moment there is nothing that can be accessed through the API that can't be accessed with TutorCruncher Socket Server, so we recommend using that.

TutorCruncher Socket Server

How do I get access to TutorCruncher socket?

Try this link.

Getting a list of tutors

If you make a request in the format below, you can get the list of the tutors you have made publically accessible.

https://socket.tutorcruncher.com/{{ YOUR_PUBLIC_API_KEY }}/contractors

If we take our demo branch as an example:

https://socket.tutorcruncher.com/9c79f14df986a1ec693c/contractors

What fields do I get on the list of tutors?

Fields Description Example
distance Used to filter your users by distance to an address/postcode
id The tutor's ID within TutorCruncher 214699
link The link that will be generated for their profile 214699-martha-s
name The tutor's name Martha S
photo A link to the tutor's profile picture https://socket.tutorcruncher.com/media/9c79f14df986a1ec693c/214699.thumb.jpg
primary_description The Extra Attribute with the name 'Primary Description', or the first extra attribute that is of type Text Long, arranged in order of priority I have been a Maths teacher (13+) since I graduated from university and tutor students outside of work. I also have experience in working with students with learning disorders.
tag_line The Extra Attribute with the name 'Tag Line', or the first extra attribute that is of type Short Text, arranged in order of priority Fantastic Maths Tutor available throughout London
town The town the tutor has listed in their address Putney
url A link to more details about that contractor (see below) https://socket.tutorcruncher.com/9c79f14df986a1ec693c/contractors/214699
country The country the tutor has entered in their address United Kingdom

How do I get more details about a tutor (like their teaching skills, other extra attributes etc)?

Going to the url link above will give you more details about the tutor.

For instance https://socket.tutorcruncher.com/9c79f14df986a1ec693c/contractors/214699

Fields Description Example
country The country the tutor has entered in their address United Kingdom
extra_attributes All of the details about extra attributes associated with the contractor that are publicly viewable. [
  {
    "machine_name": "tag-line"
    "name": "Tag Line"
    "sort_index": 0.0
    "type": "text_short"
    "value": "Fantastic Maths Tutor available throughout London"
  }
]
id The tutor's ID within TutorCruncher 214699
name The tutor's name Martha S
photo A link to the tutor's profile picture https://socket.tutorcruncher.com/media/9c79f14df986a1ec693c/214699.jpg
primary_description The Extra Attribute with the name 'Primary Description', or the first extra attribute that is of type Text Long, arranged in order of priority I have been a Maths teacher (13+) since I graduated from university and tutor students outside of work. I also have experience in working with students with learning disorders.
tag_line The Extra Attribute with the name 'Tag Line', or the first extra attribute that is of type Short Text, arranged in order of priority Fantastic Maths Tutor available throughout London
town The town the tutor has listed in their address Putney
skills The skills a tutor has listed on their profiles. [
  {
    "category": "Maths"
    "qual_levels": [
      "11+",
      "13+"
    ],
    "subject": "Mathematics"
  }
]

As you can see above, Extra Attributes and Skills are listed with other details relevant to them.

Making an enquiry

You have to use a POST request to submit the form, so we've created an example for you to browse. If you have any questions, let us know.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  </head>
  <body>
    <form action="#" method="POST">
      <input type="text" id="client_name" name="client_name" placeholder="Name (Required)" required="required" maxlength="255">
      <br><br>
      <input type="email" id="client_email" name="client_email" placeholder="Email" maxlength="255">
      <br><br>
      <input type="text" id="client_phone" name="client_phone" placeholder="Phone number" maxlength="255">
      <br><br>
      <textarea id="attributes-tell-us-about-yourself" attrtype="true" name="attributes-tell-us-about-yourself" placeholder="Tell us about yourself" maxlength="2047" rows="5"></textarea>
      <div class="g-recaptcha" data-sitekey="6LdyXRgUAAAAADUNhMVKJDXiRr6DUN8TGOgllqbt"></div>
      <button type="submit">Submit</button>
    </form>
  </body>
  <script src="https://www.google.com/recaptcha/api.js" async defer></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <script>
    $('form').submit(function(e) {
      e.preventDefault()
      var v = grecaptcha.getResponse()
      if (v.length === 0) {
        $('#captcha').html("You can't leave Captcha Code empty")
        return false
      }
      var data = {
        client_name: $('#client_name').val(),
        client_email: $('#client_email').val(),
        client_phone: $('#client_phone').val(),
        grecaptcha_response : v,
        // Make sure any extra attribute fields are in a separate object.
        attributes: {
          'attributes-tell-us-about-yourself': $('#attributes-tell-us-about-yourself').val()
        }
      }
      $.ajax({
        type: 'POST',
        url: 'https://socket.tutorcruncher.com/9c79f14df986a1ec693c/enquiry',
        data: JSON.stringify(data),
        dataType: 'json'
      }).done(function() {
        $('form').html('form successfully submitted. Sticky badge for you!')
      })
    })
  </script>
</html>

Using TutorCruncher's API

To help you get started with the API we provide a browsable version of the API which can be accessed via your browser.

To view it go to https://secure.tutorcruncher.com/api/. This root page will provide a list of all API ends points.

You may also find it helpful to use chrome's postman extension to make some trial requests to the API.

Curl Example

API authenication on TutorCruncher is performed using an HTTP request header including your API token, for example to get a list of users on your company you could make a curl request thus:

Request:

> curl -H "Authorization: token <your API token>" -H "Accept: application/json; indent=2" https://secure.tutorcruncher.com/api/users/

(Here the accept header is not required as application/json is default, obviously indent is only added to format the response in this example.)

Response:

{
  "count": 112,
  "next": "https://secure.tutorcruncher.com/api/users/?page=2",
  "previous": null,
  "results": [
    {
      "id": 123,
      "email": "frank.test@example.com",
      "title": 50,
      "first_name": "Frank",
      "last_name": "Test",
      "street": "263 St Vincent Street",
      "postcode": "SW1W 0EN",
      "town": "Leicester",
      "country": 183,
      "date_of_birth": null,
      "phone": "",
      "mobile": "",
      "gender": null,
      "photo": "https://tutorcruncher-private.s3.amazonaws.com/testagency/...<temporary link>...",
      "timezone": "Europe/London",
      "password": "<hash of password>",
      "date_created": "2015-03-03"
    },
    ...

Python Example

The following python example demonstrates very simple usage of the API. This only scratches the surface of what the API can do. To learn more try using the API with your demo branch, or contact us for assistance.

import json
from pprint import pprint
# requests (http://docs.python-requests.org/en/latest/) needs to be installed before this script will run,
# once you have python set up it should be as simple as "pip install requests"
import requests


API_URL = 'https://secure.tutorcruncher.com/api/'
API_TOKEN = 'set your API token here'
STANDARD_API_HEADERS = {'Authorization': 'Token %s' % API_TOKEN}


def list_all_contractors():
    """
    Get a list of contractors from TutorCruncher, inspect the result for details on the first contractor.
    """
    url = API_URL + 'contractors/'
    r = requests.get(url, headers=STANDARD_API_HEADERS)
    print 'contractor list status code: %r' % r.status_code  # should be 200

    con_data = r.json()
    pprint(con_data)
    print 'number of contractors: %d' % con_data['count']
    if con_data['count'] == 0:
        return
    # most of the core information for the contractor is saved on the contractor's user object,
    # so to get their name etc. we need to get the user, luckily the data here includes a link directly to the user

    first_con = con_data['results'][0]
    r = requests.get(first_con['user_link'], headers=STANDARD_API_HEADERS)
    print 'get user status code: %r' % r.status_code

    pprint(r.json())


def list_available_services():
    """
    get a list of services (jobs) which are available for application
    """
    # 20 is the status code for "available for application", see below
    url = API_URL + 'services/?status=20'
    r = requests.get(url, headers=STANDARD_API_HEADERS)

    print 'service list status code: %r' % r.status_code  # should be 200
    pprint(r.json())

    # more information is available on the meaning of different fields can how to filter by them
    # by looking at the endpoint's "options", for example we can get the 20 "available for application" value above:
    url = API_URL + 'services/'
    r = requests.options(url, headers=STANDARD_API_HEADERS)
    # WARNING: the output here is pretty long
    pprint(r.json())


def explore_api():
    """
    List all end points in the API. This give you an overview of what can be accomplished with the API.
    """
    r = requests.get(API_URL, headers=STANDARD_API_HEADERS)
    print 'status code: %r' % r.status_code  # should be 200
    pprint(r.json())


def create_contractor(verbose=True):
    """
    Create a new contractor, to do this we first have to create the user which the contractor will be associated with.
    :return: id of new contractor
    """
    # other fields are available when creating and updating users, this is just the bare minimum, see the options
    # page for more information
    data = {
        'email': 'james@example.com',
        'first_name': 'james',
        'last_name': 'blogs',
        'timezone': 'Europe/London',
    }

    url = API_URL + 'users/'
    r = requests.post(url, data=json.dumps(data), headers=STANDARD_API_HEADERS)

    if verbose:
        print 'create user status code: %r' % r.status_code  # should be 201
        pprint(r.json())
    user_id = r.json()['id']

    # as with user other fields are available, just the minimum is set here.
    data = {
        'user': user_id,
        'status': 20,  # this is the code for approved, again you can get this from options
    }

    url = API_URL + 'contractors/'
    r = requests.post(url, data=json.dumps(data), headers=STANDARD_API_HEADERS)

    con_data = r.json()
    if verbose:
        print 'create contractor status code: %r' % r.status_code  # should be 201
        pprint(con_data)
    return con_data['id']


def extra_attributes():
    """
    Create contractor as above, but also create extra attributes to record specific data about them.

    We create a new Attribute Definitions to record the contractors favourite colour.
    """
    # this extra attribute definition will refer to contractors so we need the id of the Contractor content type:
    url = API_URL + 'cts/?model=contractor'
    r = requests.get(url, headers=STANDARD_API_HEADERS)
    assert r.status_code == 200, 'problem with get request, status code %r, content:\n%r' % (r.status_code, r.content)
    data = r.json()
    assert data['count'] == 1, 'wrong number of content types returned: %r' % data
    contractor_ct_id = data['results'][0]['id']

    data = {
        'name': 'Favourite Colour',
        'content_type': '/api/cts/%d/' % contractor_ct_id,  # this field has to be supplied in the form of a url
        'attrtype': 60,  # "Dropdown", see /api/attrs/ Options for details
        'required': True,
        'drop_options': 'red,blue,green,pink,brown'
    }

    url = API_URL + 'attrs/'
    r = requests.post(url, data=json.dumps(data), headers=STANDARD_API_HEADERS)
    assert r.status_code == 201, 'problem with post request, status code %r, content:\n%r' % (r.status_code, r.content)
    av_def_id = r.json()['id']

    # take a look at the list of Attributes Definitions to see our newly created one.
    r = requests.get(url, headers=STANDARD_API_HEADERS)
    assert r.status_code == 200, 'problem with get request, status code %r, content:\n%r' % (r.status_code, r.content)
    print '\nAttribute Definitions:'
    pprint(r.json())
    con_id = create_contractor(verbose=False)

    con_attr_url = API_URL + 'contractors/%d/attrs/' % con_id
    r = requests.get(con_attr_url, headers=STANDARD_API_HEADERS)
    d = r.json()
    assert d['count'] == 0
    print '\nContractors existing attribute values:'
    pprint(d)  # no values at the moment as the contractor has just be created

    data = {
        'definition': '/api/attrs/%d/' % av_def_id,  # again url is required to reference the related item
        'value_str': 'blue'
    }
    r = requests.post(con_attr_url, data=json.dumps(data), headers=STANDARD_API_HEADERS)
    assert r.status_code == 201, 'problem with post request, status code %r, content:\n%r' % (r.status_code, r.content)

    con_attr_url = API_URL + 'contractors/%d/attrs/' % con_id
    r = requests.get(con_attr_url, headers=STANDARD_API_HEADERS)
    d = r.json()
    assert d['count'] == 1
    print '\nContractors existing attribute values including new value:'
    pprint(d)  # there should now contain the one value just created


if __name__ == '__main__':  # pragma: no cover
    print 'Getting list of contractors:'
    list_all_contractors()

    print 'Getting list of available services:'
    list_available_services()

    print 'exploring the API'
    explore_api()

    print 'creating user and contractor'
    create_contractor()