Time-off
GET Get time offs of organization users
https://focus.toggl.com/api/organizations/{organization_id}/timeoff
Returns the time off of the given organization users with personal detail stripped: each entry carries its id, the user it belongs to, the start and end of the period, and no timestamps. The approval status, policy name, and emoji are included only for a caller who holds the manage_time_off permission on the organization; they are omitted for every other caller, and the policy name and emoji are also omitted for an entry that has no category. The endpoint stays available to any member of the organization. user_id is required and repeatable, and so is the start_date/end_date window; both are dates (YYYY-MM-DD), interpreted in UTC, and end_date is inclusive of that whole day. An entry is returned when its period overlaps the window at either edge, so an entry that starts before start_date or ends after end_date is still included.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl https://focus.toggl.com/api/organizations/{organization_id}/timeoff \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodGet,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff')
req = Net::HTTP::Get.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.get('https://focus.toggl.com/api/organizations/{organization_id}/timeoff', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::GET, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
Query
| name | type | required | description |
|---|---|---|---|
| user_id | []integer | true | User IDs |
| start_date | string | true | From date (YYYY-MM-DD) |
| end_date | string | true | To date (YYYY-MM-DD) |
Response
200
| Name | Type | Description |
|---|---|---|
| items | Array of object | - |
items
| Name | Type | Description |
|---|---|---|
| emoji | string | Emoji is the emoji of the entry's time-off policy (category). Included only for a caller who holds the manage_time_off permission; omitted for everyone else and for an entry with no category. |
| end_time | string | EndTime is the RFC3339 timestamp (UTC) the time off period ends at; always after StartTime. |
| policy_name | string | PolicyName is the name of the entry's time-off policy (category). Included only for a caller who holds the manage_time_off permission; omitted for everyone else and for an entry with no category. |
| start_time | string | StartTime is the RFC3339 timestamp (UTC) the time off period starts at. |
| status | string | Status is the approval state of the entry: pending, approved, rejected or canceled. Included only for a caller who holds the manage_time_off permission; omitted for everyone else. |
| timeoff_id | integer | ID is the unique identifier of the time off entry. |
| user_id | integer | UserID is the user the time off was booked for. |
400
Invalid parameters
403
Forbidden
500
Internal Server Error
GET List members' time off balances
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances
Returns each visible member's balance as of date, today when omitted, in each active policy that has balance changes. A member sees their own, a team lead also their teams', and a caller with the organization-wide view_time_off permission everyone's. Requires view_time_off_balance or manage_time_off_balance.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodGet,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances')
req = Net::HTTP::Get.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.get('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::GET, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
Query
| name | type | required | description |
|---|---|---|---|
| user_id | []integer | false | Only these users, at most 500 |
| category_id | []integer | false | Only these policies |
| date | string | false | As-of date (YYYY-MM-DD) |
Response
200
| Name | Type | Description |
|---|---|---|
| items | Array of object | - |
items
| Name | Type | Description |
|---|---|---|
| balance | number | Balance is the sum of the as-of year's changes up to the as-of date, in days. |
| carried_over | number | CarriedOver is the sum of changes before the as-of year, in days. It does not expire. |
| scheduled | number | Scheduled is the days booked after the as-of date. Not yet subtracted from Balance. |
| taken | number | Taken is the days used in the as-of year up to the as-of date. Already subtracted from Balance. |
| time_off_category_id | integer | TimeOffCategoryID is the policy. |
| user_id | integer | UserID is the member. |
400
Invalid parameters
403
Forbidden
500
Internal Server Error
POST Adjust a member's time off balance
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances
Records a manual change to a member's balance in a policy. The user must be an active member and the policy the organization's. Requires manage_time_off_balance. Responds 201 with the recorded change.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl -X POST https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances \
-H "Content-Type: application/json" \
-d '\{"amount":"number","date":"string","note":"string","time_off_category_id":"integer","user_id":"integer"\}' \
-u <email>:<password>
bytes, err := json.Marshal('\{"amount":"number","date":"string","note":"string","time_off_category_id":"integer","user_id":"integer"\}')
if err != nil {
print(err)
}
req, err := http.NewRequest(http.MethodPost,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances", bytes.NewBuffer(bytes))
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances')
req = Net::HTTP::Post.new(uri)
req['Content-Type'] = "application/json"
req.body = \{"amount":"number","date":"string","note":"string","time_off_category_id":"integer","user_id":"integer"\}.to_json
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances", {
method: "POST",
body: \{"amount":"number","date":"string","note":"string","time_off_category_id":"integer","user_id":"integer"\},
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.post('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances', json=\{"amount":"number","date":"string","note":"string","time_off_category_id":"integer","user_id":"integer"\}, headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::POST, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances".to_string())
.json(&serde_json::json!(\{"amount":"number","date":"string","note":"string","time_off_category_id":"integer","user_id":"integer"\}))
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
Body
| Name | Type | Description |
|---|---|---|
| amount | number | Amount is the signed change in days; not zero. |
| date | string | Date is when the change takes effect, as RFC3339; its UTC day counts, and its year is the accrual year. Now when omitted. |
| note | string | Note is recorded with the change; up to 2000 characters. |
| time_off_category_id | integer | TimeOffCategoryID is the policy. |
| user_id | integer | UserID is the member. |
Response
201
Successful operation
400
Invalid parameters
403
Forbidden, or the user is not an active member
404
Policy not found
500
Internal Server Error
POST Set members' starting balances
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances/bulk
Sets each member's starting balance in one policy for the current year, in one transaction; resending the same rows changes nothing. The policy must be limited, yearly or one-off, with a yearly allowance above 0. At most 10,000 rows and 2 MiB. Rows of members not eligible for a balance are skipped and reported. Any invalid row fails the request with 422 and the row failures, and nothing is written. Requires manage_time_off_balance.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl -X POST https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances/bulk \
-H "Content-Type: application/json" \
-d '\{"category_id":"integer","rows":[\{"amount":"number","user_account_id":"integer"\}]\}' \
-u <email>:<password>
bytes, err := json.Marshal('\{"category_id":"integer","rows":[\{"amount":"number","user_account_id":"integer"\}]\}')
if err != nil {
print(err)
}
req, err := http.NewRequest(http.MethodPost,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances/bulk", bytes.NewBuffer(bytes))
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances/bulk')
req = Net::HTTP::Post.new(uri)
req['Content-Type'] = "application/json"
req.body = \{"category_id":"integer","rows":[\{"amount":"number","user_account_id":"integer"\}]\}.to_json
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances/bulk", {
method: "POST",
body: \{"category_id":"integer","rows":[\{"amount":"number","user_account_id":"integer"\}]\},
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.post('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances/bulk', json=\{"category_id":"integer","rows":[\{"amount":"number","user_account_id":"integer"\}]\}, headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::POST, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/balances/bulk".to_string())
.json(&serde_json::json!(\{"category_id":"integer","rows":[\{"amount":"number","user_account_id":"integer"\}]\}))
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
Body
| Name | Type | Description |
|---|---|---|
| category_id | integer | CategoryID is the policy: limited, yearly or one-off, with a yearly allowance above 0. |
| rows | Array of object | Rows are the members' starting balances; 1 to 10,000, each member once. |
rows
| Name | Type | Description |
|---|---|---|
| amount | number | Amount is the member's starting balance for the current year, in days: 0 to the policy's DefaultAmountPerYear plus MaxCarryOverAmount. |
| user_account_id | integer | UserAccountID is the member. |
Response
200
Written, including any skipped rows
| Name | Type | Description |
|---|---|---|
| failures | Array of object | Failures are invalid rows; any failure means nothing was written. |
| skipped | Array of object | Skipped are rows left unchanged; the other rows are still written. |
| written | integer | Written is the number of members whose starting balance was set; 0 when there are Failures. |
failures
| Name | Type | Description |
|---|---|---|
| code | string | Code is unknown_member (not in the organization), duplicate_member (listed earlier) or amount_invalid (outside the allowed range). Valid values: unknown_member, duplicate_member, amount_invalid. |
| row | integer | Row is the 1-based position in Rows. |
skipped
| Name | Type | Description |
|---|---|---|
| code | string | Code is not_eligible: the member is inactive or not assigned the Time Off module. Valid values: not_eligible. |
| row | integer | Row is the 1-based position in Rows. |
| user_account_id | integer | UserAccountID is the member. |
400
Invalid parameters
403
Forbidden
404
Policy not found
422
Invalid rows; nothing written
500
Internal Server Error
GET List time off policies
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories
Returns the organization's time off policies, archived ones included. Entries reference a policy by time_off_category_id. Requires the view_time_off_categories organization permission.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodGet,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories')
req = Net::HTTP::Get.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.get('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::GET, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
Response
200
| Name | Type | Description |
|---|---|---|
| items | Array of object | - |
items
| Name | Type | Description |
|---|---|---|
| accrual_frequency | string | AccrualFrequency is how the allowance is credited: yearly, monthly (a twelfth each month) or one_off (once, as a starting balance). Valid values: yearly, monthly, one_off. |
| allow_negative_balance | boolean | AllowNegativeBalance lets a member's own request take a limited balance below zero. |
| allowance_type | string | AllowanceType is limited, tracked against a balance, or unlimited. Valid values: limited, unlimited. |
| archived_at | string | ArchivedAt is when the policy was archived; omitted while it is active. |
| auto_approve_under_days | integer | AutoApproveUnderDays is the longest own request, in days, a member can have approved without review. A limited policy also checks the balance, so a request within the limit can still go to review. 0 turns it off. |
| carry_over_expiry_months | integer | CarryOverExpiryMonths is how many months carried-over days are meant to last; omitted when unset. Stored only, not applied yet: carried-over days do not expire. |
| created_at | string | CreatedAt is when the policy was created. |
| default_amount_per_year | integer | DefaultAmountPerYear is the yearly allowance in days. Unused by unlimited policies. |
| description | string | Description is the policy's description; null when unset. |
| emoji | string | Emoji is shown next to the name. |
| id | integer | ID is the policy's id. Entries reference it as time_off_category_id. |
| is_system_default | boolean | IsSystemDefault marks the organization's default policy, created automatically. |
| max_carry_over_amount | integer | MaxCarryOverAmount is how many unused days carry into the next year on a yearly policy. |
| name | string | Name is the policy's name. |
| organization_id | integer | OrganizationID is the organization the policy belongs to. |
| policy_link | string | PolicyLink is a URL to the written policy; omitted when unset. |
| prorate | string | Prorate is when proration was turned on; null when off. With proration, a member's first-year allowance covers only the months left after the later of this date and their join date. |
| updated_at | string | UpdatedAt is when the policy was last changed. |
400
Invalid parameters
403
Forbidden
500
Internal Server Error
POST Create a time off policy
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories
Creates a time off policy. A limited policy with an allowance credits every member assigned the Time Off module at once: this year's allowance, prorated when prorate is true, or this month's share on a monthly policy. Requires create_time_off_categories. Responds 201 with the policy.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl -X POST https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories \
-H "Content-Type: application/json" \
-d '\{"accrual_frequency":"string","allow_negative_balance":"boolean","allowance_type":"string","auto_approve_under_days":"integer","carry_over_expiry_months":"integer","default_amount_per_year":"integer","description":"string","emoji":"string","max_carry_over_amount":"integer","name":"string","policy_link":"string","prorate":"boolean"\}' \
-u <email>:<password>
bytes, err := json.Marshal('\{"accrual_frequency":"string","allow_negative_balance":"boolean","allowance_type":"string","auto_approve_under_days":"integer","carry_over_expiry_months":"integer","default_amount_per_year":"integer","description":"string","emoji":"string","max_carry_over_amount":"integer","name":"string","policy_link":"string","prorate":"boolean"\}')
if err != nil {
print(err)
}
req, err := http.NewRequest(http.MethodPost,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories", bytes.NewBuffer(bytes))
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories')
req = Net::HTTP::Post.new(uri)
req['Content-Type'] = "application/json"
req.body = \{"accrual_frequency":"string","allow_negative_balance":"boolean","allowance_type":"string","auto_approve_under_days":"integer","carry_over_expiry_months":"integer","default_amount_per_year":"integer","description":"string","emoji":"string","max_carry_over_amount":"integer","name":"string","policy_link":"string","prorate":"boolean"\}.to_json
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories", {
method: "POST",
body: \{"accrual_frequency":"string","allow_negative_balance":"boolean","allowance_type":"string","auto_approve_under_days":"integer","carry_over_expiry_months":"integer","default_amount_per_year":"integer","description":"string","emoji":"string","max_carry_over_amount":"integer","name":"string","policy_link":"string","prorate":"boolean"\},
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.post('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories', json=\{"accrual_frequency":"string","allow_negative_balance":"boolean","allowance_type":"string","auto_approve_under_days":"integer","carry_over_expiry_months":"integer","default_amount_per_year":"integer","description":"string","emoji":"string","max_carry_over_amount":"integer","name":"string","policy_link":"string","prorate":"boolean"\}, headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::POST, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories".to_string())
.json(&serde_json::json!(\{"accrual_frequency":"string","allow_negative_balance":"boolean","allowance_type":"string","auto_approve_under_days":"integer","carry_over_expiry_months":"integer","default_amount_per_year":"integer","description":"string","emoji":"string","max_carry_over_amount":"integer","name":"string","policy_link":"string","prorate":"boolean"\}))
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
Body
| Name | Type | Description |
|---|---|---|
| accrual_frequency | string | AccrualFrequency is how the allowance is credited: yearly (default), monthly (a twelfth each month) or one_off (once, as a starting balance). Unlimited policies are always one_off. Fixed after creation. Valid values: yearly, monthly, one_off. |
| allow_negative_balance | boolean | AllowNegativeBalance lets a member's own request take a limited balance below zero. |
| allowance_type | string | AllowanceType is limited (default), tracked against a balance, or unlimited. Fixed after creation. Valid values: limited, unlimited. |
| auto_approve_under_days | integer | AutoApproveUnderDays is the longest own request, in days, a member can have approved without review. A limited policy also checks the balance. 0 turns it off. |
| carry_over_expiry_months | integer | CarryOverExpiryMonths is how many months carried-over days are meant to last, at least 1. Stored only, not applied yet: carried-over days do not expire. |
| default_amount_per_year | integer | DefaultAmountPerYear is the yearly allowance in days, up to 999. Unused by unlimited policies. |
| description | string | Description is the policy's description; up to 1000 characters. |
| emoji | string | Emoji is shown next to the name. |
| max_carry_over_amount | integer | MaxCarryOverAmount is how many unused days carry into the next year on a yearly policy, up to 999. |
| name | string | Name is the policy's name; up to 255 characters. |
| policy_link | string | PolicyLink is a URL to the written policy; up to 2048 characters. |
| prorate | boolean | Prorate true sets the proration date to now, also when proration is already on; false turns it off. With proration, a member's first-year allowance covers only the months left after the later of that date and their join date. |
Response
201
Successful operation
400
Invalid parameters
403
Forbidden
500
Internal Server Error
GET Get a time off policy
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}
Returns one time off policy. Requires the view_time_off_categories organization permission.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id} \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodGet,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}')
req = Net::HTTP::Get.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.get('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::GET, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
| category_id | integer | true | Policy ID |
Response
200
| Name | Type | Description |
|---|---|---|
| accrual_frequency | string | AccrualFrequency is how the allowance is credited: yearly, monthly (a twelfth each month) or one_off (once, as a starting balance). Valid values: yearly, monthly, one_off. |
| allow_negative_balance | boolean | AllowNegativeBalance lets a member's own request take a limited balance below zero. |
| allowance_type | string | AllowanceType is limited, tracked against a balance, or unlimited. Valid values: limited, unlimited. |
| archived_at | string | ArchivedAt is when the policy was archived; omitted while it is active. |
| auto_approve_under_days | integer | AutoApproveUnderDays is the longest own request, in days, a member can have approved without review. A limited policy also checks the balance, so a request within the limit can still go to review. 0 turns it off. |
| carry_over_expiry_months | integer | CarryOverExpiryMonths is how many months carried-over days are meant to last; omitted when unset. Stored only, not applied yet: carried-over days do not expire. |
| created_at | string | CreatedAt is when the policy was created. |
| default_amount_per_year | integer | DefaultAmountPerYear is the yearly allowance in days. Unused by unlimited policies. |
| description | string | Description is the policy's description; null when unset. |
| emoji | string | Emoji is shown next to the name. |
| id | integer | ID is the policy's id. Entries reference it as time_off_category_id. |
| is_system_default | boolean | IsSystemDefault marks the organization's default policy, created automatically. |
| max_carry_over_amount | integer | MaxCarryOverAmount is how many unused days carry into the next year on a yearly policy. |
| name | string | Name is the policy's name. |
| organization_id | integer | OrganizationID is the organization the policy belongs to. |
| policy_link | string | PolicyLink is a URL to the written policy; omitted when unset. |
| prorate | string | Prorate is when proration was turned on; null when off. With proration, a member's first-year allowance covers only the months left after the later of this date and their join date. |
| updated_at | string | UpdatedAt is when the policy was last changed. |
400
Invalid parameters
403
Forbidden
404
Policy not found
500
Internal Server Error
PUT Update a time off policy
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}
Replaces a policy's settings. Send every field: an omitted one is cleared or zeroed. The policy as read is the template, except that prorate is sent as true or false; true sets the proration date to the request time, also when proration is already on. accrual_frequency and allowance_type cannot change. Requires update_time_off_categories.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl -X PUT https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id} \
-H "Content-Type: application/json" \
-d '\{"allow_negative_balance":"boolean","auto_approve_under_days":"integer","carry_over_expiry_months":"integer","default_amount_per_year":"integer","description":"string","emoji":"string","max_carry_over_amount":"integer","name":"string","policy_link":"string","prorate":"boolean"\}' \
-u <email>:<password>
bytes, err := json.Marshal('\{"allow_negative_balance":"boolean","auto_approve_under_days":"integer","carry_over_expiry_months":"integer","default_amount_per_year":"integer","description":"string","emoji":"string","max_carry_over_amount":"integer","name":"string","policy_link":"string","prorate":"boolean"\}')
if err != nil {
print(err)
}
req, err := http.NewRequest(http.MethodPut,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}", bytes.NewBuffer(bytes))
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}')
req = Net::HTTP::Put.new(uri)
req['Content-Type'] = "application/json"
req.body = \{"allow_negative_balance":"boolean","auto_approve_under_days":"integer","carry_over_expiry_months":"integer","default_amount_per_year":"integer","description":"string","emoji":"string","max_carry_over_amount":"integer","name":"string","policy_link":"string","prorate":"boolean"\}.to_json
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}", {
method: "PUT",
body: \{"allow_negative_balance":"boolean","auto_approve_under_days":"integer","carry_over_expiry_months":"integer","default_amount_per_year":"integer","description":"string","emoji":"string","max_carry_over_amount":"integer","name":"string","policy_link":"string","prorate":"boolean"\},
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.put('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}', json=\{"allow_negative_balance":"boolean","auto_approve_under_days":"integer","carry_over_expiry_months":"integer","default_amount_per_year":"integer","description":"string","emoji":"string","max_carry_over_amount":"integer","name":"string","policy_link":"string","prorate":"boolean"\}, headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::PUT, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}".to_string())
.json(&serde_json::json!(\{"allow_negative_balance":"boolean","auto_approve_under_days":"integer","carry_over_expiry_months":"integer","default_amount_per_year":"integer","description":"string","emoji":"string","max_carry_over_amount":"integer","name":"string","policy_link":"string","prorate":"boolean"\}))
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
| category_id | integer | true | Policy ID |
Body
| Name | Type | Description |
|---|---|---|
| allow_negative_balance | boolean | AllowNegativeBalance lets a member's own request take a limited balance below zero. |
| auto_approve_under_days | integer | AutoApproveUnderDays is the longest own request, in days, a member can have approved without review. A limited policy also checks the balance. 0 turns it off. |
| carry_over_expiry_months | integer | CarryOverExpiryMonths is how many months carried-over days are meant to last, at least 1. Stored only, not applied yet: carried-over days do not expire. |
| default_amount_per_year | integer | DefaultAmountPerYear is the yearly allowance in days, up to 999. Unused by unlimited policies. |
| description | string | Description is the policy's description; up to 1000 characters. |
| emoji | string | Emoji is shown next to the name. |
| max_carry_over_amount | integer | MaxCarryOverAmount is how many unused days carry into the next year on a yearly policy, up to 999. |
| name | string | Name is the policy's name; up to 255 characters. |
| policy_link | string | PolicyLink is a URL to the written policy; up to 2048 characters. |
| prorate | boolean | Prorate true sets the proration date to now, also when proration is already on; false turns it off. With proration, a member's first-year allowance covers only the months left after the later of that date and their join date. |
Response
200
| Name | Type | Description |
|---|---|---|
| accrual_frequency | string | AccrualFrequency is how the allowance is credited: yearly, monthly (a twelfth each month) or one_off (once, as a starting balance). Valid values: yearly, monthly, one_off. |
| allow_negative_balance | boolean | AllowNegativeBalance lets a member's own request take a limited balance below zero. |
| allowance_type | string | AllowanceType is limited, tracked against a balance, or unlimited. Valid values: limited, unlimited. |
| archived_at | string | ArchivedAt is when the policy was archived; omitted while it is active. |
| auto_approve_under_days | integer | AutoApproveUnderDays is the longest own request, in days, a member can have approved without review. A limited policy also checks the balance, so a request within the limit can still go to review. 0 turns it off. |
| carry_over_expiry_months | integer | CarryOverExpiryMonths is how many months carried-over days are meant to last; omitted when unset. Stored only, not applied yet: carried-over days do not expire. |
| created_at | string | CreatedAt is when the policy was created. |
| default_amount_per_year | integer | DefaultAmountPerYear is the yearly allowance in days. Unused by unlimited policies. |
| description | string | Description is the policy's description; null when unset. |
| emoji | string | Emoji is shown next to the name. |
| id | integer | ID is the policy's id. Entries reference it as time_off_category_id. |
| is_system_default | boolean | IsSystemDefault marks the organization's default policy, created automatically. |
| max_carry_over_amount | integer | MaxCarryOverAmount is how many unused days carry into the next year on a yearly policy. |
| name | string | Name is the policy's name. |
| organization_id | integer | OrganizationID is the organization the policy belongs to. |
| policy_link | string | PolicyLink is a URL to the written policy; omitted when unset. |
| prorate | string | Prorate is when proration was turned on; null when off. With proration, a member's first-year allowance covers only the months left after the later of this date and their join date. |
| updated_at | string | UpdatedAt is when the policy was last changed. |
400
Invalid parameters
403
Forbidden
404
Policy not found
500
Internal Server Error
DELETE Delete a time off policy
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}
Deletes a policy no entry uses. Answers 409 with time_off_category_in_use when one does or time_off_category_system_default for the default policy. Requires delete_time_off_categories.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl -X DELETE https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id} \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodPut,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}')
req = Net::HTTP::Delete.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}", {
method: "DELETE",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.delete('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::DELETE, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
| category_id | integer | true | Policy ID |
Response
204
No content
400
Invalid parameters
403
Forbidden
404
Policy not found
409
Policy in use or default policy
500
Internal Server Error
POST Archive a time off policy
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}/archive
Archives a policy. Requires update_time_off_categories.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl -X POST https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}/archive \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodPost,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}/archive")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}/archive')
req = Net::HTTP::Post.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}/archive", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.post('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}/archive', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::POST, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}/archive".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
| category_id | integer | true | Policy ID |
Response
200
| Name | Type | Description |
|---|---|---|
| accrual_frequency | string | AccrualFrequency is how the allowance is credited: yearly, monthly (a twelfth each month) or one_off (once, as a starting balance). Valid values: yearly, monthly, one_off. |
| allow_negative_balance | boolean | AllowNegativeBalance lets a member's own request take a limited balance below zero. |
| allowance_type | string | AllowanceType is limited, tracked against a balance, or unlimited. Valid values: limited, unlimited. |
| archived_at | string | ArchivedAt is when the policy was archived; omitted while it is active. |
| auto_approve_under_days | integer | AutoApproveUnderDays is the longest own request, in days, a member can have approved without review. A limited policy also checks the balance, so a request within the limit can still go to review. 0 turns it off. |
| carry_over_expiry_months | integer | CarryOverExpiryMonths is how many months carried-over days are meant to last; omitted when unset. Stored only, not applied yet: carried-over days do not expire. |
| created_at | string | CreatedAt is when the policy was created. |
| default_amount_per_year | integer | DefaultAmountPerYear is the yearly allowance in days. Unused by unlimited policies. |
| description | string | Description is the policy's description; null when unset. |
| emoji | string | Emoji is shown next to the name. |
| id | integer | ID is the policy's id. Entries reference it as time_off_category_id. |
| is_system_default | boolean | IsSystemDefault marks the organization's default policy, created automatically. |
| max_carry_over_amount | integer | MaxCarryOverAmount is how many unused days carry into the next year on a yearly policy. |
| name | string | Name is the policy's name. |
| organization_id | integer | OrganizationID is the organization the policy belongs to. |
| policy_link | string | PolicyLink is a URL to the written policy; omitted when unset. |
| prorate | string | Prorate is when proration was turned on; null when off. With proration, a member's first-year allowance covers only the months left after the later of this date and their join date. |
| updated_at | string | UpdatedAt is when the policy was last changed. |
400
Invalid parameters
403
Forbidden
404
Policy not found
500
Internal Server Error
POST Restore a time off policy
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}/restore
Restores an archived policy. Requires update_time_off_categories.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl -X POST https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}/restore \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodPost,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}/restore")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}/restore')
req = Net::HTTP::Post.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}/restore", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.post('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}/restore', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::POST, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/categories/{category_id}/restore".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
| category_id | integer | true | Policy ID |
Response
200
| Name | Type | Description |
|---|---|---|
| accrual_frequency | string | AccrualFrequency is how the allowance is credited: yearly, monthly (a twelfth each month) or one_off (once, as a starting balance). Valid values: yearly, monthly, one_off. |
| allow_negative_balance | boolean | AllowNegativeBalance lets a member's own request take a limited balance below zero. |
| allowance_type | string | AllowanceType is limited, tracked against a balance, or unlimited. Valid values: limited, unlimited. |
| archived_at | string | ArchivedAt is when the policy was archived; omitted while it is active. |
| auto_approve_under_days | integer | AutoApproveUnderDays is the longest own request, in days, a member can have approved without review. A limited policy also checks the balance, so a request within the limit can still go to review. 0 turns it off. |
| carry_over_expiry_months | integer | CarryOverExpiryMonths is how many months carried-over days are meant to last; omitted when unset. Stored only, not applied yet: carried-over days do not expire. |
| created_at | string | CreatedAt is when the policy was created. |
| default_amount_per_year | integer | DefaultAmountPerYear is the yearly allowance in days. Unused by unlimited policies. |
| description | string | Description is the policy's description; null when unset. |
| emoji | string | Emoji is shown next to the name. |
| id | integer | ID is the policy's id. Entries reference it as time_off_category_id. |
| is_system_default | boolean | IsSystemDefault marks the organization's default policy, created automatically. |
| max_carry_over_amount | integer | MaxCarryOverAmount is how many unused days carry into the next year on a yearly policy. |
| name | string | Name is the policy's name. |
| organization_id | integer | OrganizationID is the organization the policy belongs to. |
| policy_link | string | PolicyLink is a URL to the written policy; omitted when unset. |
| prorate | string | Prorate is when proration was turned on; null when off. With proration, a member's first-year allowance covers only the months left after the later of this date and their join date. |
| updated_at | string | UpdatedAt is when the policy was last changed. |
400
Invalid parameters
403
Forbidden
404
Policy not found
500
Internal Server Error
GET List time off entries
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries
Returns a page of time off entries, latest start first, in any status unless filtered. A member sees their own entries, a team lead also their teams', and a caller with the organization-wide view_time_off permission everyone's; filters only narrow that set. from and to select entries overlapping the days between them, both included. id is the value the per-user entry endpoints call timeoff_id; dates carry no offset and are UTC.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodGet,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries')
req = Net::HTTP::Get.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.get('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::GET, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
Query
| name | type | required | description |
|---|---|---|---|
| user_id | []integer | false | Only these users |
| team_id | integer | false | Only this team; the caller must lead it or view the whole organization |
| category_id | integer | false | Only this policy |
| status | []string | false | Only these statuses: pending, approved, rejected, canceled |
| from | string | false | Window start (YYYY-MM-DD) |
| to | string | false | Window end (YYYY-MM-DD) |
| page | integer | false | Page number, from 1 |
| rows | integer | false | Page size, 1 to 500 (default 50) |
Response
200
| Name | Type | Description |
|---|---|---|
| data | Array of object | Data is the page's entries. |
| page | integer | Page is the 1-based page number. |
| rows | integer | Rows is the page size. |
| total | integer | Total is the number of entries across all pages; omitted when zero. |
data
| Name | Type | Description |
|---|---|---|
| approved_at | string | ApprovedAt is when the entry was approved; omitted when it never was, and for entries created through the API. |
| approver_email | string | ApproverEmail is the approver's email; empty without an approver. |
| approver_id | integer | ApproverID is the member who approved or rejected the entry; omitted when no member did. |
| approver_name | string | ApproverName is the approver's name; empty without an approver. |
| approver_user_account_id | integer | ApproverUserAccountID equals ApproverID. |
| created_at | string | CreatedAt is when the entry was created. |
| created_by | integer | CreatedBy is the member who created the entry; omitted when not recorded. |
| creator_email | string | CreatorEmail is the creator's email; empty when CreatedBy is omitted. |
| creator_name | string | CreatorName is the creator's name; empty when CreatedBy is omitted. |
| daily_breakdown | Array of object | DailyBreakdown is the entry's day-by-day count; empty when it has none. |
| days_taken | number | DaysTaken is the entry's day count, the sum of DailyBreakdown. |
| end_date | string | EndDate is the day the entry ends, in UTC: YYYY-MM-DDT00:00:00. |
| id | integer | ID is the entry's id; the per-user entry endpoints call it timeoff_id. |
| note | string | Note is the requester's note. |
| organization_id | integer | OrganizationID is the entry's organization. |
| rejection_reason | string | RejectionReason is the reason given on rejection; empty otherwise. |
| requester_email | string | RequesterEmail is the member's email. |
| requester_name | string | RequesterName is the member's name. |
| requester_user_account_id | integer | RequesterUserAccountID is the entry's member; equals UserID. |
| start_date | string | StartDate is when the entry starts, in UTC without an offset: YYYY-MM-DDTHH:MM:SS. |
| status | string | Status is the approval state. Valid values: pending, approved, rejected, canceled. |
| time_off_category_id | integer | TimeOffCategoryID is the entry's policy; omitted when it has none. |
| updated_at | string | UpdatedAt is when the entry was last changed. |
| user_id | integer | UserID is the member the entry belongs to. |
daily_breakdown
| Name | Type | Description |
|---|---|---|
| date | string | Date is the day, in UTC: YYYY-MM-DDT00:00:00. |
| taken | number | Taken is the part of the day taken, 0 to 1. |
400
Invalid parameters
403
Forbidden
500
Internal Server Error
GET Get a time off entry
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}
Returns one time off entry in any status, with the names and emails of its requester, approver and creator. Open to the entry's owner, a team lead of the owner, and a caller with the organization-wide view_time_off permission.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id} \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodGet,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}')
req = Net::HTTP::Get.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.get('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::GET, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
| entry_id | integer | true | Entry ID |
Response
200
| Name | Type | Description |
|---|---|---|
| approved_at | string | ApprovedAt is when the entry was approved; omitted when it never was, and for entries created through the API. |
| approver_email | string | ApproverEmail is the approver's email; empty without an approver. |
| approver_id | integer | ApproverID is the member who approved or rejected the entry; omitted when no member did. |
| approver_name | string | ApproverName is the approver's name; empty without an approver. |
| approver_user_account_id | integer | ApproverUserAccountID equals ApproverID. |
| created_at | string | CreatedAt is when the entry was created. |
| created_by | integer | CreatedBy is the member who created the entry; omitted when not recorded. |
| creator_email | string | CreatorEmail is the creator's email; empty when CreatedBy is omitted. |
| creator_name | string | CreatorName is the creator's name; empty when CreatedBy is omitted. |
| daily_breakdown | Array of object | DailyBreakdown is the entry's day-by-day count; empty when it has none. |
| days_taken | number | DaysTaken is the entry's day count, the sum of DailyBreakdown. |
| end_date | string | EndDate is the day the entry ends, in UTC: YYYY-MM-DDT00:00:00. |
| id | integer | ID is the entry's id; the per-user entry endpoints call it timeoff_id. |
| note | string | Note is the requester's note. |
| organization_id | integer | OrganizationID is the entry's organization. |
| rejection_reason | string | RejectionReason is the reason given on rejection; empty otherwise. |
| requester_email | string | RequesterEmail is the member's email. |
| requester_name | string | RequesterName is the member's name. |
| requester_user_account_id | integer | RequesterUserAccountID is the entry's member; equals UserID. |
| start_date | string | StartDate is when the entry starts, in UTC without an offset: YYYY-MM-DDTHH:MM:SS. |
| status | string | Status is the approval state. Valid values: pending, approved, rejected, canceled. |
| time_off_category_id | integer | TimeOffCategoryID is the entry's policy; omitted when it has none. |
| updated_at | string | UpdatedAt is when the entry was last changed. |
| user_id | integer | UserID is the member the entry belongs to. |
daily_breakdown
| Name | Type | Description |
|---|---|---|
| date | string | Date is the day, in UTC: YYYY-MM-DDT00:00:00. |
| taken | number | Taken is the part of the day taken, 0 to 1. |
400
Invalid parameters
403
Forbidden
404
Entry not found
500
Internal Server Error
PUT Approve a time off entry
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/approve
Approves a pending entry, charges its days to the requester's balance in its policy, and notifies the requester as the web app does. Requires the organization-wide approve_time_off permission or leading a team of the requester. Answers 409 when the entry is not pending.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl -X PUT https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/approve \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodPut,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/approve")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/approve')
req = Net::HTTP::Put.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/approve", {
method: "PUT",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.put('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/approve', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::PUT, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/approve".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
| entry_id | integer | true | Entry ID |
Response
200
| Name | Type | Description |
|---|---|---|
| approved_at | string | ApprovedAt is when the entry was approved; omitted when it never was, and for entries created through the API. |
| approver_id | integer | ApproverID is the member who approved or rejected the entry; omitted when no member did. |
| created_at | string | CreatedAt is when the entry was created. |
| created_by | integer | CreatedBy is the member who created the entry; omitted when not recorded. |
| daily_breakdown | Array of object | DailyBreakdown is the entry's day-by-day count; empty when it has none. |
| days_taken | number | DaysTaken is the entry's day count, the sum of DailyBreakdown. |
| end_date | string | EndDate is the day the entry ends, in UTC: YYYY-MM-DDT00:00:00. |
| id | integer | ID is the entry's id; the per-user entry endpoints call it timeoff_id. |
| note | string | Note is the requester's note. |
| organization_id | integer | OrganizationID is the entry's organization. |
| rejection_reason | string | RejectionReason is the reason given on rejection; empty otherwise. |
| start_date | string | StartDate is when the entry starts, in UTC without an offset: YYYY-MM-DDTHH:MM:SS. |
| status | string | Status is the approval state. Valid values: pending, approved, rejected, canceled. |
| time_off_category_id | integer | TimeOffCategoryID is the entry's policy; omitted when it has none. |
| updated_at | string | UpdatedAt is when the entry was last changed. |
| user_id | integer | UserID is the member the entry belongs to. |
daily_breakdown
| Name | Type | Description |
|---|---|---|
| date | string | Date is the day, in UTC: YYYY-MM-DDT00:00:00. |
| taken | number | Taken is the part of the day taken, 0 to 1. |
400
Invalid parameters
403
Forbidden
404
Entry not found
409
Entry not pending
500
Internal Server Error
PUT Cancel a time off entry
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/cancel
Cancels a pending or approved entry and returns any days it charged. Notifies the requester unless they cancel it themselves. Open to the entry's owner, a team lead of the owner, and a caller with the organization-wide cancel_time_off permission. Answers 409 when the entry is already rejected or canceled.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl -X PUT https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/cancel \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodPut,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/cancel")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/cancel')
req = Net::HTTP::Put.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/cancel", {
method: "PUT",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.put('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/cancel', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::PUT, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/cancel".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
| entry_id | integer | true | Entry ID |
Response
200
| Name | Type | Description |
|---|---|---|
| approved_at | string | ApprovedAt is when the entry was approved; omitted when it never was, and for entries created through the API. |
| approver_id | integer | ApproverID is the member who approved or rejected the entry; omitted when no member did. |
| created_at | string | CreatedAt is when the entry was created. |
| created_by | integer | CreatedBy is the member who created the entry; omitted when not recorded. |
| daily_breakdown | Array of object | DailyBreakdown is the entry's day-by-day count; empty when it has none. |
| days_taken | number | DaysTaken is the entry's day count, the sum of DailyBreakdown. |
| end_date | string | EndDate is the day the entry ends, in UTC: YYYY-MM-DDT00:00:00. |
| id | integer | ID is the entry's id; the per-user entry endpoints call it timeoff_id. |
| note | string | Note is the requester's note. |
| organization_id | integer | OrganizationID is the entry's organization. |
| rejection_reason | string | RejectionReason is the reason given on rejection; empty otherwise. |
| start_date | string | StartDate is when the entry starts, in UTC without an offset: YYYY-MM-DDTHH:MM:SS. |
| status | string | Status is the approval state. Valid values: pending, approved, rejected, canceled. |
| time_off_category_id | integer | TimeOffCategoryID is the entry's policy; omitted when it has none. |
| updated_at | string | UpdatedAt is when the entry was last changed. |
| user_id | integer | UserID is the member the entry belongs to. |
daily_breakdown
| Name | Type | Description |
|---|---|---|
| date | string | Date is the day, in UTC: YYYY-MM-DDT00:00:00. |
| taken | number | Taken is the part of the day taken, 0 to 1. |
400
Invalid parameters
403
Forbidden
404
Entry not found
409
Entry already rejected or canceled
500
Internal Server Error
PUT Reject a time off entry
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/reject
Rejects a pending entry and notifies the requester, with the reason when given, as the web app does. The body is optional. Access as for approving. Answers 409 when the entry is not pending.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl -X PUT https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/reject \
-H "Content-Type: application/json" \
-d '\{"reason":"string"\}' \
-u <email>:<password>
bytes, err := json.Marshal('\{"reason":"string"\}')
if err != nil {
print(err)
}
req, err := http.NewRequest(http.MethodPut,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/reject", bytes.NewBuffer(bytes))
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/reject')
req = Net::HTTP::Put.new(uri)
req['Content-Type'] = "application/json"
req.body = \{"reason":"string"\}.to_json
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/reject", {
method: "PUT",
body: \{"reason":"string"\},
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.put('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/reject', json=\{"reason":"string"\}, headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::PUT, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/entries/{entry_id}/reject".to_string())
.json(&serde_json::json!(\{"reason":"string"\}))
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
| entry_id | integer | true | Entry ID |
Body
| Name | Type | Description |
|---|---|---|
| reason | string | Reason is shown to the requester; optional. |
Response
200
| Name | Type | Description |
|---|---|---|
| approved_at | string | ApprovedAt is when the entry was approved; omitted when it never was, and for entries created through the API. |
| approver_id | integer | ApproverID is the member who approved or rejected the entry; omitted when no member did. |
| created_at | string | CreatedAt is when the entry was created. |
| created_by | integer | CreatedBy is the member who created the entry; omitted when not recorded. |
| daily_breakdown | Array of object | DailyBreakdown is the entry's day-by-day count; empty when it has none. |
| days_taken | number | DaysTaken is the entry's day count, the sum of DailyBreakdown. |
| end_date | string | EndDate is the day the entry ends, in UTC: YYYY-MM-DDT00:00:00. |
| id | integer | ID is the entry's id; the per-user entry endpoints call it timeoff_id. |
| note | string | Note is the requester's note. |
| organization_id | integer | OrganizationID is the entry's organization. |
| rejection_reason | string | RejectionReason is the reason given on rejection; empty otherwise. |
| start_date | string | StartDate is when the entry starts, in UTC without an offset: YYYY-MM-DDTHH:MM:SS. |
| status | string | Status is the approval state. Valid values: pending, approved, rejected, canceled. |
| time_off_category_id | integer | TimeOffCategoryID is the entry's policy; omitted when it has none. |
| updated_at | string | UpdatedAt is when the entry was last changed. |
| user_id | integer | UserID is the member the entry belongs to. |
daily_breakdown
| Name | Type | Description |
|---|---|---|
| date | string | Date is the day, in UTC: YYYY-MM-DDT00:00:00. |
| taken | number | Taken is the part of the day taken, 0 to 1. |
400
Invalid parameters
403
Forbidden
404
Entry not found
409
Entry not pending
500
Internal Server Error
GET Get the absence report
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/reports/absence
Returns leave and balances per member and policy over a period of at most 732 days: balance figures as of end_date, and leave inside the period split at today. Covers everyone for a caller with the organization-wide view_time_off permission, the led teams for a team lead, otherwise the caller alone. Requires view_time_off_balance or manage_time_off_balance.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl https://focus.toggl.com/api/organizations/{organization_id}/timeoff/reports/absence \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodGet,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/reports/absence")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/reports/absence')
req = Net::HTTP::Get.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/reports/absence", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.get('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/reports/absence', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::GET, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/reports/absence".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
Query
| name | type | required | description |
|---|---|---|---|
| start_date | string | true | Period start (YYYY-MM-DD) |
| end_date | string | true | Period end (YYYY-MM-DD) |
| user_id | []integer | false | Only these users |
| team_id | []integer | false | Only these teams, at most 50 |
| category_id | []integer | false | Only these policies |
| include_pending | boolean | false | Count pending leave as scheduled |
Response
200
| Name | Type | Description |
|---|---|---|
| end_date | string | EndDate is the period's last day: YYYY-MM-DD. |
| rows | Array of object | Rows has one row per member and active policy with any non-zero figure, by member name. |
| start_date | string | StartDate is the period's first day: YYYY-MM-DD. |
| totals | object | Totals sums Rows. |
rows
| Name | Type | Description |
|---|---|---|
| absence_rate | number | AbsenceRate is TakenInPeriod divided by WorkingDaysInPeriod. |
| allowance_type | string | AllowanceType is the policy's allowance type. Valid values: limited, unlimited. |
| balance | number | Balance is the sum of changes in EndDate's year up to EndDate, in days; 0 for an unlimited policy. |
| category_emoji | string | CategoryEmoji is the policy's emoji. |
| category_id | integer | CategoryID is the policy. |
| category_name | string | CategoryName is the policy's name. |
| scheduled_after_period_end | number | ScheduledAfterPeriodEnd is the days entries charge after EndDate. |
| scheduled_in_period | number | ScheduledInPeriod is the approved leave days in the period after today, plus pending ones when requested. |
| taken_in_period | number | TakenInPeriod is the approved leave days in the period up to today. |
| taken_through_period_end | number | TakenThroughPeriodEnd is the days entries charged in EndDate's year up to EndDate. |
| user_id | integer | UserID is the member. |
| user_name | string | UserName is the member's name. |
| working_days_in_period | integer | WorkingDaysInPeriod is the Monday to Friday days in the period. |
totals
| Name | Type | Description |
|---|---|---|
| absence_rate | number | AbsenceRate is TakenInPeriod divided by working days times UserCount. |
| balance | number | Balance sums the rows' Balance. |
| scheduled_after_period_end | number | ScheduledAfterPeriodEnd sums the rows' ScheduledAfterPeriodEnd. |
| scheduled_in_period | number | ScheduledInPeriod sums the rows' ScheduledInPeriod. |
| taken_in_period | number | TakenInPeriod sums the rows' TakenInPeriod. |
| taken_through_period_end | number | TakenThroughPeriodEnd sums the rows' TakenThroughPeriodEnd. |
| user_count | integer | UserCount is the members the report covers, including those without rows. |
400
Invalid parameters
403
Forbidden
500
Internal Server Error
GET List the time off timeline
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/timeline
Returns the time off entries overlapping the days from from to to, both included, ordered by start: pending and approved unless status says otherwise. Visibility and filters as in the entries list; no pagination.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl https://focus.toggl.com/api/organizations/{organization_id}/timeoff/timeline \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodGet,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/timeline")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/timeline')
req = Net::HTTP::Get.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/timeline", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.get('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/timeline', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::GET, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/timeline".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
Query
| name | type | required | description |
|---|---|---|---|
| user_id | []integer | false | Only these users |
| team_id | integer | false | Only this team; the caller must lead it or view the whole organization |
| category_id | integer | false | Only this policy |
| status | []string | false | Only these statuses: pending, approved, rejected, canceled |
| from | string | false | Window start (YYYY-MM-DD) |
| to | string | false | Window end (YYYY-MM-DD) |
Response
200
| Name | Type | Description |
|---|---|---|
| items | Array of object | - |
items
| Name | Type | Description |
|---|---|---|
| days_span | integer | DaysSpan is the number of calendar days from StartDate to EndDate, both included. |
| days_taken | number | DaysTaken is the entry's day count. |
| end_date | string | EndDate is the day the entry ends, in UTC: YYYY-MM-DDT00:00:00. |
| id | integer | ID is the entry's id. |
| requester_name | string | RequesterName is the member's name. |
| start_date | string | StartDate is the entry's first day, in UTC: YYYY-MM-DDT00:00:00. |
| status | string | Status is the approval state. Valid values: pending, approved, rejected, canceled. |
| time_off_category_id | integer | TimeOffCategoryID is the entry's policy; omitted when it has none. |
| user_id | integer | UserID is the member the entry belongs to. |
400
Invalid parameters
403
Forbidden
500
Internal Server Error
GET Get time off for organization user
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}
Returns the full time off entries of one organization user, including the category and the creation and last-modification timestamps. Requires the manage_time_off organization permission — this applies to reading as well, and to a caller's own entries. The from/to window is required; both are dates (YYYY-MM-DD), interpreted in UTC, and to is inclusive of that whole day. An entry is returned when its period overlaps the window at either edge, so an entry that starts before from or ends after to is still included.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id} \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodGet,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}')
req = Net::HTTP::Get.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.get('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::GET, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
| user_id | integer | true | User ID |
Query
| name | type | required | description |
|---|---|---|---|
| from | string | true | From date (YYYY-MM-DD) |
| to | string | true | To date (YYYY-MM-DD) |
Response
200
| Name | Type | Description |
|---|---|---|
| items | Array of object | - |
items
| Name | Type | Description |
|---|---|---|
| created_at | string | CreatedAt is the RFC3339 timestamp (UTC) the entry was created at. |
| daily_breakdown | Array of object | DailyBreakdown is the entry's day-by-day count. Omitted when the entry has none. |
| days_taken | number | DaysTaken is the entry's day count, the sum of DailyBreakdown. Omitted when zero. |
| emoji | string | Emoji is the emoji of the entry's time-off policy (category). Omitted from create and update responses and for an entry without a policy. |
| end_time | string | EndTime is the RFC3339 timestamp (UTC) the time off period ends at; always after StartTime. |
| organization_id | integer | OrganizationID is the organization the entry belongs to. |
| policy_name | string | PolicyName is the name of the entry's time-off policy (category). Omitted from create and update responses and for an entry without a policy. |
| start_time | string | StartTime is the RFC3339 timestamp (UTC) the time off period starts at. |
| status | string | Status is the approval state of the entry: pending, approved, rejected or canceled. |
| time_off_category_id | integer | TimeOffCategoryID is the id of the entry's time-off policy (category). Omitted when the entry has no policy. |
| timeoff_id | integer | ID is the unique identifier of the time off entry. |
| type | string | Type is the legacy type enum: vacation, sick, parental or other. Independent of TimeOffCategoryID; omitted when unset. |
| updated_at | string | UpdatedAt is the RFC3339 timestamp (UTC) the entry was last modified at. |
| user_id | integer | UserID is the user the time off was booked for. |
daily_breakdown
| Name | Type | Description |
|---|---|---|
| date | string | Date is the day, as an RFC3339 timestamp at 00:00 UTC. |
| taken | number | Taken is the part of the day taken, from 0 to 1: 1 for a full day, 0.5 for a half day, 0 for a weekend or holiday. |
400
Invalid parameters
403
Forbidden
500
Internal Server Error
PUT Update time off for the specified user
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}
Updates one or more existing time off entries of the specified user in a single call. The request body is an array: each element identifies the entry by its timeoff_id and carries the new start_time and end_time (RFC3339) plus an optional type, time_off_category_id and daily_breakdown. Omitting type clears it. Omitting time_off_category_id or daily_breakdown keeps the stored value; a kept breakdown must still fall within the new dates, or the request fails with a 400. Include each timeoff_id at most once: with duplicates, which element wins is undefined. Elements whose timeoff_id does not match an entry of the user are skipped. All elements are applied in a single transaction: if applying them would leave any two of the user's approved or pending time off entries overlapping (entries created through this API are approved), the whole request fails with a 409 and nothing is updated. Requires the manage_time_off organization permission. Responds 200 with the entries that were actually updated.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl -X PUT https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id} \
-H "Content-Type: application/json" \
-d '[\{"daily_breakdown":[\{"date":"string","taken":"number"\}],"end_time":"string","start_time":"string","time_off_category_id":"integer","timeoff_id":"integer","type":"string"\}]' \
-u <email>:<password>
bytes, err := json.Marshal('[\{"daily_breakdown":[\{"date":"string","taken":"number"\}],"end_time":"string","start_time":"string","time_off_category_id":"integer","timeoff_id":"integer","type":"string"\}]')
if err != nil {
print(err)
}
req, err := http.NewRequest(http.MethodPut,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}", bytes.NewBuffer(bytes))
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}')
req = Net::HTTP::Put.new(uri)
req['Content-Type'] = "application/json"
req.body = [\{"daily_breakdown":[\{"date":"string","taken":"number"\}],"end_time":"string","start_time":"string","time_off_category_id":"integer","timeoff_id":"integer","type":"string"\}].to_json
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}", {
method: "PUT",
body: [\{"daily_breakdown":[\{"date":"string","taken":"number"\}],"end_time":"string","start_time":"string","time_off_category_id":"integer","timeoff_id":"integer","type":"string"\}],
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.put('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}', json=[\{"daily_breakdown":[\{"date":"string","taken":"number"\}],"end_time":"string","start_time":"string","time_off_category_id":"integer","timeoff_id":"integer","type":"string"\}], headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::PUT, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}".to_string())
.json(&serde_json::json!([\{"daily_breakdown":[\{"date":"string","taken":"number"\}],"end_time":"string","start_time":"string","time_off_category_id":"integer","timeoff_id":"integer","type":"string"\}]))
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
| user_id | integer | true | User ID |
Body
| Name | Type | Description |
|---|---|---|
| items | Array of object | - |
items
| Name | Type | Description |
|---|---|---|
| daily_breakdown | Array of object | DailyBreakdown replaces the entry's day-by-day count, with the same rules as on create. Omit it to keep the stored one, which must then still fall within the new dates. |
| end_time | string | EndTime is the RFC3339 timestamp the time off period ends at; must be after StartTime. Send it in UTC: offsets are discarded, not converted. |
| start_time | string | StartTime is the RFC3339 timestamp the time off period starts at. Send it in UTC: offsets are discarded, not converted. |
| time_off_category_id | integer | TimeOffCategoryID is the id of an organization time-off policy (category). It must belong to the organization; omit to keep the entry's stored policy. |
| timeoff_id | integer | ID is the unique identifier of the time off entry to update. |
| type | string | Type is the optional legacy type enum: vacation, sick, parental or other. Omitting it clears the stored type; TimeOffCategoryID is unaffected. Valid values: vacation, sick, parental, other. |
daily_breakdown
| Name | Type | Description |
|---|---|---|
| date | string | Date is the day, as an RFC3339 timestamp at 00:00 UTC. |
| taken | number | Taken is the part of the day taken, from 0 to 1: 1 for a full day, 0.5 for a half day, 0 for a weekend or holiday. |
Response
200
| Name | Type | Description |
|---|---|---|
| items | Array of object | - |
items
| Name | Type | Description |
|---|---|---|
| created_at | string | CreatedAt is the RFC3339 timestamp (UTC) the entry was created at. |
| daily_breakdown | Array of object | DailyBreakdown is the entry's day-by-day count. Omitted when the entry has none. |
| days_taken | number | DaysTaken is the entry's day count, the sum of DailyBreakdown. Omitted when zero. |
| emoji | string | Emoji is the emoji of the entry's time-off policy (category). Omitted from create and update responses and for an entry without a policy. |
| end_time | string | EndTime is the RFC3339 timestamp (UTC) the time off period ends at; always after StartTime. |
| organization_id | integer | OrganizationID is the organization the entry belongs to. |
| policy_name | string | PolicyName is the name of the entry's time-off policy (category). Omitted from create and update responses and for an entry without a policy. |
| start_time | string | StartTime is the RFC3339 timestamp (UTC) the time off period starts at. |
| status | string | Status is the approval state of the entry: pending, approved, rejected or canceled. |
| time_off_category_id | integer | TimeOffCategoryID is the id of the entry's time-off policy (category). Omitted when the entry has no policy. |
| timeoff_id | integer | ID is the unique identifier of the time off entry. |
| type | string | Type is the legacy type enum: vacation, sick, parental or other. Independent of TimeOffCategoryID; omitted when unset. |
| updated_at | string | UpdatedAt is the RFC3339 timestamp (UTC) the entry was last modified at. |
| user_id | integer | UserID is the user the time off was booked for. |
daily_breakdown
| Name | Type | Description |
|---|---|---|
| date | string | Date is the day, as an RFC3339 timestamp at 00:00 UTC. |
| taken | number | Taken is the part of the day taken, from 0 to 1: 1 for a full day, 0.5 for a half day, 0 for a weekend or holiday. |
400
Invalid parameters
403
Forbidden
409
Overlapping time off entry
500
Internal Server Error
POST Create time off for the specified user
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}
Creates one or more time off entries for the specified user in a single call. The request body is an array: each element needs a start_time and an end_time (RFC3339) and may carry a policy (time_off_category_id), a daily_breakdown and a legacy type. The sum of daily_breakdown is the entry's day count, charged to the user's balance in its policy and counted in the absence report; an entry without a breakdown counts 0 days. All elements are created in a single transaction: a period that overlaps one of the user's approved or pending time off entries — or another element of the same request — fails the whole request with a 409 and nothing is created (entries created through this API are approved). Requires the manage_time_off organization permission. Responds 200 with the created entries, each including the id it was assigned.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl -X POST https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id} \
-H "Content-Type: application/json" \
-d '[\{"daily_breakdown":[\{"date":"string","taken":"number"\}],"end_time":"string","start_time":"string","time_off_category_id":"integer","type":"string"\}]' \
-u <email>:<password>
bytes, err := json.Marshal('[\{"daily_breakdown":[\{"date":"string","taken":"number"\}],"end_time":"string","start_time":"string","time_off_category_id":"integer","type":"string"\}]')
if err != nil {
print(err)
}
req, err := http.NewRequest(http.MethodPost,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}", bytes.NewBuffer(bytes))
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}')
req = Net::HTTP::Post.new(uri)
req['Content-Type'] = "application/json"
req.body = [\{"daily_breakdown":[\{"date":"string","taken":"number"\}],"end_time":"string","start_time":"string","time_off_category_id":"integer","type":"string"\}].to_json
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}", {
method: "POST",
body: [\{"daily_breakdown":[\{"date":"string","taken":"number"\}],"end_time":"string","start_time":"string","time_off_category_id":"integer","type":"string"\}],
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.post('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}', json=[\{"daily_breakdown":[\{"date":"string","taken":"number"\}],"end_time":"string","start_time":"string","time_off_category_id":"integer","type":"string"\}], headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::POST, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}".to_string())
.json(&serde_json::json!([\{"daily_breakdown":[\{"date":"string","taken":"number"\}],"end_time":"string","start_time":"string","time_off_category_id":"integer","type":"string"\}]))
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
| user_id | integer | true | User ID |
Body
| Name | Type | Description |
|---|---|---|
| items | Array of object | - |
items
| Name | Type | Description |
|---|---|---|
| daily_breakdown | Array of object | DailyBreakdown is the entry's day-by-day count: each date within the entry, at most once. Its sum is the entry's day count, charged to the member's balance when the entry has a policy. Omit it and the entry counts 0 days. |
| end_time | string | EndTime is the RFC3339 timestamp the time off period ends at; must be after StartTime. Send it in UTC: offsets are discarded, not converted. |
| start_time | string | StartTime is the RFC3339 timestamp the time off period starts at. Send it in UTC: offsets are discarded, not converted. |
| time_off_category_id | integer | TimeOffCategoryID is the id of an organization time-off policy (category) to attach. It must belong to the organization; omit to leave the entry without a policy. |
| type | string | Type is the optional legacy type enum: vacation, sick, parental or other. Independent of TimeOffCategoryID. Valid values: vacation, sick, parental, other. |
daily_breakdown
| Name | Type | Description |
|---|---|---|
| date | string | Date is the day, as an RFC3339 timestamp at 00:00 UTC. |
| taken | number | Taken is the part of the day taken, from 0 to 1: 1 for a full day, 0.5 for a half day, 0 for a weekend or holiday. |
Response
200
| Name | Type | Description |
|---|---|---|
| items | Array of object | - |
items
| Name | Type | Description |
|---|---|---|
| created_at | string | CreatedAt is the RFC3339 timestamp (UTC) the entry was created at. |
| daily_breakdown | Array of object | DailyBreakdown is the entry's day-by-day count. Omitted when the entry has none. |
| days_taken | number | DaysTaken is the entry's day count, the sum of DailyBreakdown. Omitted when zero. |
| emoji | string | Emoji is the emoji of the entry's time-off policy (category). Omitted from create and update responses and for an entry without a policy. |
| end_time | string | EndTime is the RFC3339 timestamp (UTC) the time off period ends at; always after StartTime. |
| organization_id | integer | OrganizationID is the organization the entry belongs to. |
| policy_name | string | PolicyName is the name of the entry's time-off policy (category). Omitted from create and update responses and for an entry without a policy. |
| start_time | string | StartTime is the RFC3339 timestamp (UTC) the time off period starts at. |
| status | string | Status is the approval state of the entry: pending, approved, rejected or canceled. |
| time_off_category_id | integer | TimeOffCategoryID is the id of the entry's time-off policy (category). Omitted when the entry has no policy. |
| timeoff_id | integer | ID is the unique identifier of the time off entry. |
| type | string | Type is the legacy type enum: vacation, sick, parental or other. Independent of TimeOffCategoryID; omitted when unset. |
| updated_at | string | UpdatedAt is the RFC3339 timestamp (UTC) the entry was last modified at. |
| user_id | integer | UserID is the user the time off was booked for. |
daily_breakdown
| Name | Type | Description |
|---|---|---|
| date | string | Date is the day, as an RFC3339 timestamp at 00:00 UTC. |
| taken | number | Taken is the part of the day taken, from 0 to 1: 1 for a full day, 0.5 for a half day, 0 for a weekend or holiday. |
400
Invalid parameters
403
Forbidden
409
Overlapping time off entry
500
Internal Server Error
DELETE Delete time off for the specified user
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}
Deletes one or more time off entries of the specified user. The request body is an array of time off ids. Ids that do not match an entry of the user are skipped silently — the response does not indicate how many entries were deleted. Requires the manage_time_off organization permission. Responds 204 with no body.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl -X DELETE https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id} \
-H "Content-Type: application/json" \
-d '[\{\}]' \
-u <email>:<password>
bytes, err := json.Marshal('[\{\}]')
if err != nil {
print(err)
}
req, err := http.NewRequest(http.MethodPut,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}", bytes.NewBuffer(bytes))
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}')
req = Net::HTTP::Delete.new(uri)
req['Content-Type'] = "application/json"
req.body = [\{\}].to_json
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}", {
method: "DELETE",
body: [\{\}],
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.delete('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}', json=[\{\}], headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::DELETE, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}".to_string())
.json(&serde_json::json!([\{\}]))
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
| user_id | integer | true | User ID |
Body
| Name | Type | Description |
|---|---|---|
| items | Array of integer | - |
Response
204
No Content
400
Invalid parameters
403
Forbidden
500
Internal Server Error
GET Get a user's time off balances
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}/balances
Returns the user's balance as of date, today when omitted, in each active policy that has balance changes; unlimited policies usually have none and are then absent. Requires view_time_off_balance or manage_time_off_balance. A member reads only their own balances, a team lead their team's, and a caller with organization-wide view_time_off anyone's.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}/balances \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodGet,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}/balances")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}/balances')
req = Net::HTTP::Get.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}/balances", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.get('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}/balances', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::GET, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}/balances".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
| user_id | integer | true | User ID |
Query
| name | type | required | description |
|---|---|---|---|
| category_id | integer | false | Only this policy |
| date | string | false | As-of date (YYYY-MM-DD) |
Response
200
| Name | Type | Description |
|---|---|---|
| items | Array of object | - |
items
| Name | Type | Description |
|---|---|---|
| balance | number | Balance is the sum of the as-of year's changes up to the as-of date, in days. |
| carried_over | number | CarriedOver is the sum of changes before the as-of year, in days. It does not expire. |
| scheduled | number | Scheduled is the days booked after the as-of date. Not yet subtracted from Balance. |
| taken | number | Taken is the days used in the as-of year up to the as-of date. Already subtracted from Balance. |
| time_off_category_id | integer | TimeOffCategoryID is the policy. |
400
Invalid parameters
403
Forbidden
500
Internal Server Error
GET List a user's time off balance changes
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}/balances/changes
Returns a page of the user's balance changes in one policy that are already in effect, newest first. Access follows the balances endpoint.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}/balances/changes \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodGet,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}/balances/changes")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}/balances/changes')
req = Net::HTTP::Get.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}/balances/changes", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.get('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}/balances/changes', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::GET, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/users/{user_id}/balances/changes".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
| user_id | integer | true | User ID |
Query
| name | type | required | description |
|---|---|---|---|
| category_id | integer | true | Policy ID |
| year | integer | false | Only this accrual year |
| page | integer | false | Page number, from 1 |
| rows | integer | false | Page size, 1 to 500 (default 50) |
Response
200
| Name | Type | Description |
|---|---|---|
| data | Array of object | Data is the page's changes. |
| page | integer | Page is the 1-based page number. |
| rows | integer | Rows is the page size. |
| total | integer | Total is the number of changes across all pages; omitted when zero. |
data
| Name | Type | Description |
|---|---|---|
| accrual_month | integer | AccrualMonth is the month of a monthly accrual; omitted otherwise. |
| accrual_year | integer | AccrualYear is the year the change counts toward. |
| amount | number | Amount is the signed change in days. |
| created_at | string | CreatedAt is when the change was recorded. |
| created_by | integer | CreatedBy is the account id of the member who made the change; omitted for automatic changes. |
| effective_date | string | EffectiveDate is the day the change takes effect. |
| id | integer | ID is the change's id. |
| note | string | Note is the note recorded with the change; empty on used changes. |
| remaining_balance | number | RemainingBalance is the policy balance after this change. |
| time_off_category_id | integer | TimeOffCategoryID is the policy. |
| time_off_end_date | string | TimeOffEndDate is the end of the entry that used the days; set on used changes only. |
| time_off_id | integer | TimeOffID is the entry that used the days; set on used changes only. |
| time_off_start_date | string | TimeOffStartDate is the start of the entry that used the days; set on used changes only. |
| type | string | Type is earned (accrual), used (by an entry), adjustment (manual), initial_seed (starting balance) or carry_over (days above MaxCarryOverAmount removed at the new year). Valid values: earned, used, adjustment, initial_seed, carry_over. |
400
Invalid parameters
403
Forbidden
500
Internal Server Error
GET List who's out
https://focus.toggl.com/api/organizations/{organization_id}/timeoff/whos-out
Returns every active member's pending and approved time off overlapping start_date to end_date, both included, at most 7 days. Open to any member of the organization.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl https://focus.toggl.com/api/organizations/{organization_id}/timeoff/whos-out \
-H "Content-Type: application/json" \
-u <email>:<password>
req, err := http.NewRequest(http.MethodGet,
"https://focus.toggl.com/api/organizations/{organization_id}/timeoff/whos-out")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.SetBasicAuth("<email>", "<password>")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
print(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print(err)
}
fmt.Print(string(body))
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/whos-out')
req = Net::HTTP::Get.new(uri)
req['Content-Type'] = "application/json"
req.basic_auth '<email>', '<password>'
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end
puts JSON.parse(res.body)
fetch("https://focus.toggl.com/api/organizations/{organization_id}/timeoff/whos-out", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Basic ${base64.encode(<email>:<password>)}`
},
})
.then((resp) => resp.json())
.then((json) => {
console.log(json);
})
.catch(err => console.error(err));
import requests
from base64 import b64encode
data = requests.get('https://focus.toggl.com/api/organizations/{organization_id}/timeoff/whos-out', headers={'content-type': 'application/json', 'Authorization' : 'Basic %s' % b64encode(b"<email>:<password>").decode("ascii")})
print(data.json())
extern crate tokio;
extern crate serde_json;
use reqwest::{Client};
use reqwest::header::{CONTENT_TYPE};
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = Client::new().basic_auth("<email>", "<password>");
let json = client.request(Method::GET, "https://focus.toggl.com/api/organizations/{organization_id}/timeoff/whos-out".to_string())
.header(CONTENT_TYPE, "application/json")
.send()
.await?
.json()
.await?;
println!("{:#?}", json);
Ok(())
}
Parameters
Path
| name | type | required | description |
|---|---|---|---|
| organization_id | integer | true | Organization ID |
Query
| name | type | required | description |
|---|---|---|---|
| start_date | string | true | Window start (YYYY-MM-DD) |
| end_date | string | true | Window end (YYYY-MM-DD) |
Response
200
| Name | Type | Description |
|---|---|---|
| items | Array of object | - |
items
| Name | Type | Description |
|---|---|---|
| display_name | string | DisplayName is the member's name. |
| end_date | string | EndDate is the absence's last day: YYYY-MM-DD. |
| id | integer | ID is the entry's id. |
| start_date | string | StartDate is the absence's first day: YYYY-MM-DD. |
| user_account_id | integer | UserAccountID is the absent member. |
400
Invalid parameters
403
Forbidden
500
Internal Server Error