API V2 Documentation beta

Read data from BeeBole or write data to BeeBole


Warning: The API v2 is in beta and will replace the first version of our API (API V1 documentation). Both versions currently co-exist but we encourage you to start using the API v2 if you are starting to integrate our app.

Introduction

Welcome to the BeeBole API documentation.

The goal of the API is to open the data associated with your account and give you the possibility to integrate with or to build custom applications (time entry gadget, reports, ...). The API provides a full set of services allowing you to create, update, list and delete time entries in your timesheet.

Table of Contents

If you have any question or problem, please contact us

Authentication

To enable the API, go to your account, and click the top right menu: Settings.
Then locate the module: Account.
Click the line labelled: Enable/Disable API calls.
And tick the box to enable the API for your account, as below:

Enable/Disable API

Then, each user will find their respective token in the 'API Token' module. From there it will be also possible to reset it and get a new one:

API Token

For every API request, you'll need to present this token using basic HTTP authentication. You will use the token in the username field of the HTTP authorization header. The password field will always be "x".

Here is how you will define your authorization's HTTP header:

1) a username:password pair:
"803b433162432915ce2e7b25a022910925ab73c2:x"
2) base64 encode it:
"ODAzYjQzMzE2MjQzMjkxNWNlMmU3YjI1YTAyMjkxMDkyNWFiNzNjMjp4"

3) ... and here is your HTTP authorization header:
"Authorization: Basic ODAzYjQzMzE2MjQzMjkxNWNlMmU3YjI1YTAyMjkxMDkyNWFiNzNjMjp4"

Back to top

Limits

To prevent errors and abuses, we limited the API access by user both in terms of:

  • transfer volume: 2048KB/day
  • and number of requests: 4000 requests/day

If you reach this limit feel free to contact us

Back to top

Request

BeeBole is accepting HTTP POST resquests in a JSON format to the following URL:

https://yourAccount.beebole-apps.com/api/v2

Don't forget the https as all the BeeBole API communication with the server will be encrypted.

Data should be UTF-8 encoded.
Date and time values are of the form YYYY-MM-DD HH:MM:SS.

Each request will be composed of a "service" node and the rest of parameters.
Example:

1
2
3
4
{
"service": "absence.list",
"company": {"id": 233}
}

Note: in order to quickly test the API calls, we encourage you to install and use cURL. Here is the curl command corresponding to the code portion above:
curl -k -X POST https://803b433162432915ce2e7b25a022910925ab73c2:x@yourClientAlias.beebole-apps.com/api/v2 -d '{"service":"absence.list", "company":{"id":3}}'

Back to top

Response

Each response will return a "status" node with the value "ok" or "error". Along with an error status you will always find a "message" node containing an explanation of what the error is.

Examples:

request to the server

1
2
3
4
{
  "status": "ok",
  "absences": [ ... ]
}

response from the server

1
2
3
4
{
  "status": "error",
  "message": "Invalid service request ..."
}
Back to top

External Ids

In order to integrate BeeBole with an existing solution, it's possible to set the entity ids manually.
If the id's are coming from another system than BeeBole:

  • send xid along with each create request (example 1)
  • then replace id with xid in all requests and responses(example 2)

Examples:

Example 1 : create request to the server

1
2
3
4
5
6
7
{
  "service" : "company.create",
  "company" : {
    "xid" : "56478",
    "name" : "myCompany"
  }
}

response

1
2
3
4
{
  "status" : "ok",
  "xid" : "56478"
}

Example 2 : get request to the server

1
2
3
4
{
  "service" : "company.get",
  "xid" : "56478"
}

response

1
2
3
4
5
6
7
8
9
10
11
{
  "status" : "ok",
  "company" : {
    "xid" : "56478",
    "name" : "myCompany",
    "active" : true,
    "projects": {
      "count" : 3
    }
  }
}
Back to top

Absence

absence.create


1
2
3
4
5
6
7
{
  "service": "absence.create",
  "absence": {
    "name": "myAbsence",
    "company": {"id": 233}
  }
}


1
2
3
4
{     
  "status": "ok",
  "id": 78
}

absence.get


1
2
3
4
{
  "service": "absence.get",
  "id": 78
}


1
2
3
4
5
6
7
8
9
{
  "status" : "ok",
  "absence" : {
    "id" : 78,
    "name" : "myAbsence",
    "company" : {"id" : 233},
    "active" : true
  }
}

absence.update


1
2
3
4
5
6
7
{
  "service" : "absence.update",
  "absence" : {
    "id" : 78,
    "name" : "newName"
  }
}


1
{"status" : "ok"}

absence.list


1
2
3
4
{
  "service": "absence.list",
  "company" : {"id" : 233}
}


1
2
3
4
5
6
7
8
9
10
11
{
  "status" : "ok",
  "absences": [
    {
      "id" : 78,
      "name" : "myAbsence",
      "company": {id : 233},
      "active" : true
    }, ...
  ]	
}

absence.activate


1
2
3
4
{
  "service": "absence.activate",
  "id": 78
}


1
{"status": "ok"}

absence.deactivate


1
2
3
4
{
  "service": "absence.deactivate",
  "id": 78
}


1
{"status": "ok"}
Back to top

Company

company.create


1
2
3
4
5
6
{
  "service": "company.create",
  "company": {
    "name": "myCompany"
  }
}


1
2
3
4
{     
  "status": "ok",
  "id": 233
}

company.get


1
2
3
4
{
  "service": "company.get",
  "id": 233
}


1
2
3
4
5
6
7
8
9
10
11
{
  "status" : "ok",
  "company" : {
    "id" : 233,
    "name" : "myCompany",
    "projects": {
      "count": 3
    },
    "active" : true
  }
}

company.update


1
2
3
4
5
6
7
{
  "service" : "company.update",
  "company" : {
    "id" : 233,
    "name" : "newName"
  }
}


1
{"status" : "ok"}

company.list


1
2
3
{
  "service": "company.list"
}


1
2
3
4
5
6
7
8
9
10
11
{
  "status" : "ok",
  "companies": [
    {
      "id" : 233,
      "name" : "myCompany",
      "projects": {"count": 3},
      "active" : true
    }, ...
  ]	
}

company.activate


1
2
3
4
{
  "service": "company.activate",
  "id": 233
}


1
{"status": "ok"}

company.deactivate


1
2
3
4
{
  "service": "company.deactivate",
  "id": 233
}


1
{"status": "ok"}
Back to top

Person

person.create


1
2
3
4
5
6
7
{
  "service": "person.create",
  "person": {
    "name": "Rosa Parks",
    "company": {"id": 233}
  }
}


1
2
3
4
{     
  "status": "ok",
  "id": 455
}

person.get


1
2
3
4
{
  "service": "person.get",
  "id": 455
}


1
2
3
4
5
6
7
8
9
{
  "status" : "ok",
  "person" : {
    "id" : 455,
    "name" : "Rosa Parks",
    "company" : {"id" : 233},
    "active" : true
  }
}

person.update


1
2
3
4
5
6
7
{
  "service" : "person.update",
  "absence" : {
    "id" : 455,
    "name" : "newName"
  }
}


1
{"status" : "ok"}

person.list


1
2
3
4
{
  "service": "person.list",
  "company" : {"id" : 233}
}


1
2
3
4
5
6
7
8
9
10
11
{
  "status": "ok",
  "people": [
    {
      "id": 455,
      "name" : "Rosa Parks",
      "company": {id : 233},
      "active" : true
    }, ...
  ]	
}

person.activate


1
2
3
4
{
  "service": "person.activate",
  "id": 455
}


1
{"status": "ok"}

person.deactivate


1
2
3
4
{
  "service": "person.deactivate",
  "id": 455
}


1
{"status": "ok"}
Back to top

Project

project.create


1
2
3
4
5
6
7
{
  "service": "project.create",
  "project": {
    "name": "Development",
    "company": {"id": 233}
  }
}


1
2
3
4
{     
  "status": "ok",
  "id": 321
}

project.get


1
2
3
4
{
  "service": "project.get",
  "id": 321
}


1
2
3
4
5
6
7
8
9
10
{
  "status" : "ok",
  "project" : {
    "id" : 321,
    "name" : "Development",
    "company" : {"id" : 233},
    "subprojects" : {"count" : 2},
    "active" : true
  }
}

project.update


1
2
3
4
5
6
7
{
  "service" : "project.update",
  "project" : {
    "id" : 321,
    "name" : "newName"
  }
}


1
{"status" : "ok"}

project.list


1
2
3
4
{
  "service": "project.list",
  "company" : {"id" : 233}
}


1
2
3
4
5
6
7
8
9
10
11
12
{
  "status": "ok",
  "projects": [
    {
      "id": 321,
      "name" : "Development",
      "company": {id : 233},
      "subprojects" : {"count" : 2},
      "active" : true
    }, ...
  ]	
}

project.activate


1
2
3
4
{
  "service": "project.activate",
  "id": 321
}


1
{"status": "ok"}

project.deactivate


1
2
3
4
{
  "service": "project.deactivate",
  "id": 321
}


1
{"status": "ok"}
Back to top

Subproject

subproject.create


1
2
3
4
5
6
7
{
  "service": "subproject.create",
  "subproject": {
    "name": "Prototype",
    "project": {"id": 321}
  }
}


1
2
3
4
{     
  "status": "ok",
  "id": 765
}

subproject.get


1
2
3
4
{
  "service": "subproject.get",
  "id": 765
}


1
2
3
4
5
6
7
8
9
{
  "status" : "ok",
  "subproject" : {
    "id" : 765,
    "name" : "Prototype",
    "project" : {"id" : 765},
    "active" : true
  }
}

subproject.update


1
2
3
4
5
6
7
{
  "service" : "subproject.update",
  "subproject" : {
    "id" : 765,
    "name" : "newName"
  }
}


1
{"status" : "ok"}

subproject.list


1
2
3
4
{
  "service": "subproject.list",
  "project" : {"id" : 765}
}


1
2
3
4
5
6
7
8
9
10
11
{
  "status": "ok",
  "subprojects": [
    {
      "id" : 765,
      "name" : "Prototype",
      "project" : {"id" : 765},
      "active" : true
    }, ...
  ]	
}

subproject.activate


1
2
3
4
{
  "service": "subproject.activate",
  "id": 765
}


1
{"status": "ok"}

subproject.deactivate


1
2
3
4
{
  "service": "subproject.deactivate",
  "id": 765
}


1
{"status": "ok"}
Back to top

Task

task.create


1
2
3
4
5
6
7
{
  "service": "task.create",
  "task": {
    "name": "Meeting",
    "company": {"id": 233}
  }
}


1
2
3
4
{     
  "status": "ok",
  "id": 955
}

task.get


1
2
3
4
{
  "service": "task.get",
  "id": 955
}


1
2
3
4
5
6
7
8
9
{
  "status" : "ok",
  "task" : {
    "id" : 955,
    "name" : "Meeting",
    "company" : {"id" : 233},
    "active" : true
  }
}

task.update


1
2
3
4
5
6
7
{
  "service" : "task.update",
  "task" : {
    "id" : 955,
    "name" : "newName"
  }
}


1
{"status" : "ok"}

task.list


1
2
3
4
{
  "service": "task.list",
  "company" : {"id" : 233}
}


1
2
3
4
5
6
7
8
9
10
11
{
  "status": "ok",
  "tasks": [
    {
      "id" : 955,
      "name" : "Meeting",
      "company" : {"id" : 233},
      "active" : true
    }, ...
  ]	
}

task.activate


1
2
3
4
{
  "service": "task.activate",
  "id": 955
}


1
{"status": "ok"}

task.deactivate


1
2
3
4
{
  "service": "task.deactivate",
  "id": 955
}


1
{"status": "ok"}
Back to top

Time

This section deals with the timesheet entries retrieval.

The API exposes the following two services in order to retrieve the time records :

  • The service time_entry.export initiates and launch an export job. This job is queued and is processed in the background. The service's response will be a new job object. The job object is composed with a unique ID, its status and, if it has been completed, a result.
  • If the previous service didn't respond with a result, the service time_entry.get_job_info will be used to query the job status and get the final result. As for the export service, it will return a job object.

How to use those services ?

1 - call the service time_entry.export to initiate a new export job and receive a new job ID.

2 - call the service time_entry.get_job_info periodically (each 5 sec) in order to check if the job has been done and if the response contains a result. You should exit the loop on a service status or a job.status == "error", or when the job.status == "done" and job.result is of type string.

time_entry.export

This service initiates a new export job. This job is queued and processed in the background.

The service wraps the in app export module functionality.

Parameters :

"from" and "to" : each call is limited to a time range of one month (up to 31 days).

"show" and "keys" : those two parameters are linked. The "show" parameter represents what kind of report you want to get. Depending of the "show" parameter, you will adapt the "keys" parameter which represents the columns you want to export :

show
keys
abs (Absence) all (Working Time &Absence) quota (Absence Quotas) work (Working Time)
company x x x x
companyId x x x x
person x x x x
personId x x x x
project x x x
projectId x x x
subproject x x x
subprojectId x x x
absence x x x x
absenceId x x x x
task x x x
taskId x x x
hours x x x
date x x x
inDays x x x x
billing x x x
cost x x x
status x x x
comment x x x
hourlyRate x x x
dailyRate x x x
available x
balance x
taken x
fromTo x

"statusFilers" : this represents the time record filter.

a approved
d draft
l locked
r rejected
s submitted


1
2
3
4
5
6
7
8
{
  "service": "time_entry.export",
  "from": "2013-10-01",
  "to" : "2013-10-30",
  "show" : "all", // Optional default "all",
  "keys" : ["company", "companyId", "hours"],
  "statusFilters" : ["l", "a"], //optional
}


1
2
3
4
5
6
7
{
  "status":"ok",
  "job": {
    "status":"running",
    "id":1148
  }
}

time_entry.get_job_info


1
2
3
4
{
  "service":"time_entry.get_job_info",
  "id":1148
}


1
2
3
4
5
6
7
{
  "status":"ok",
  "job": {
    "status":"running",
    "id":1148
  }
}

OR if it's done
1
2
3
4
5
6
7
8
{
  "status":"ok",
  "job": {
    "status":"done",
    "id":1148,
    "result":"Entreprise,Heures\nBranch,\"7,000\"\nMyCompany,\"63,000\"\n ..."
  }
}
Back to top