Subscriptions
GET Get current subscription
https://focus.toggl.com/api/organizations/{organization_id}/subscriptions/current
Get current subscription.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl https://focus.toggl.com/api/organizations/{organization_id}/subscriptions/current \
-H "Content-Type: application/json"
req, err := http.NewRequest(http.MethodGet,
"https://focus.toggl.com/api/organizations/{organization_id}/subscriptions/current")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
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}/subscriptions/current')
req = Net::HTTP::Get.new(uri)
req['Content-Type'] = "application/json"
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}/subscriptions/current", {
method: "GET",
headers: {
"Content-Type": "application/json"
},
})
.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}/subscriptions/current', headers={'content-type': 'application/json'})
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();
let json = client.request(Method::GET, "https://focus.toggl.com/api/organizations/{organization_id}/subscriptions/current".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 |
|---|---|---|
| focus_trial_ended_at | string | null |
| granted | boolean | Granted reports an entitlement the organization holds without paying for it: the Stripe-backed fields are empty because no Stripe subscription backs the grant. |
| organization_id | integer | - |
| price | object | - |
| product | object | - |
| subscription | object | - |
| subscription_item | object | - |
| track_subscription | object | - |
price
| Name | Type | Description |
|---|---|---|
| billing_period_in_months | integer | - |
| cost_in_cents | integer | - |
| currency | string | - |
| tag | string | - |
| track_pricing_plan_id | integer | - |
product
| Name | Type | Description |
|---|---|---|
| handle | string | - |
| name | string | - |
| site | string | - |
| toggl_product_id | string | - |
| track_enterprise | boolean | - |
| track_plan_id | integer | - |
subscription
| Name | Type | Description |
|---|---|---|
| customer | object | - |
| id | string | - |
| payment_failed | boolean | - |
| state | string | - |
| subscription_item | object | - |
| url | string | - |
customer
| Name | Type | Description |
|---|---|---|
| id | string | - |
| url | string | - |
subscription_item
| Name | Type | Description |
|---|---|---|
| discount | object | - |
| quantity | integer | Quantity is the live paid quantity (number of paid licenses). |
| scheduled_quantity | integer | ScheduledQuantity is the scheduled next-cycle quantity when a change is pending in Stripe (typically a decrease); nil when there is no pending change — no schedule, or the scheduled quantity equals the live quantity. |
| subscription_item_id | string | ID is the Stripe subscription item ID. Empty for trial-only synthetic responses where no Stripe subscription item exists yet. |
| updated_at | string | - |
discount
| Name | Type | Description |
|---|---|---|
| amount_off | integer | - |
| coupon_id | string | - |
| currency | string | - |
| duration | string | - |
| name | string | - |
| percent_off | number | - |
| promotion_code_id | string | - |
subscription_item
| Name | Type | Description |
|---|---|---|
| discount | object | - |
| quantity | integer | Quantity is the live paid quantity (number of paid licenses). |
| scheduled_quantity | integer | ScheduledQuantity is the scheduled next-cycle quantity when a change is pending in Stripe (typically a decrease); nil when there is no pending change — no schedule, or the scheduled quantity equals the live quantity. |
| subscription_item_id | string | ID is the Stripe subscription item ID. Empty for trial-only synthetic responses where no Stripe subscription item exists yet. |
| updated_at | string | - |
discount
| Name | Type | Description |
|---|---|---|
| amount_off | integer | - |
| coupon_id | string | - |
| currency | string | - |
| duration | string | - |
| name | string | - |
| percent_off | number | - |
| promotion_code_id | string | - |
track_subscription
| Name | Type | Description |
|---|---|---|
| cancel_date | string | - |
| current_period_ends_at | string | - |
| current_period_starts_at | string | - |
| end_date | string | - |
| pause_starts_at | string | - |
| paused | boolean | Paused is true while the organization is in the unpaid months of a self-serve pause, which is when products make it read-only; the subscription itself stays "active". PauseStartsAt is the first skipped renewal, where those months start, and ResumesAt the renewal billing restarts at. Both are set from the moment the pause applies until billing restarts or the customer resumes, so clients can show a pause that has not started yet. |
| payment_failed | boolean | - |
| resumes_at | string | - |
| start_date | string | - |
| subscription_created_at | string | - |
| subscription_updated_at | string | - |
| trial | object | - |
trial
| Name | Type | Description |
|---|---|---|
| available | boolean | - |
| end_date | string | - |
| start_date | string | - |
| trial_plan_id | integer | - |
400
Invalid request
403
Insufficient permissions
500
Internal Server Error
GET Get current trial
https://focus.toggl.com/api/organizations/{organization_id}/subscriptions/trials/current
Get the organization's current active Focus plan trial. Add-on module trials (Capacity, Time Off) are excluded: they run alongside the organization's own plan rather than standing in for it.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl https://focus.toggl.com/api/organizations/{organization_id}/subscriptions/trials/current \
-H "Content-Type: application/json"
req, err := http.NewRequest(http.MethodGet,
"https://focus.toggl.com/api/organizations/{organization_id}/subscriptions/trials/current")
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
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}/subscriptions/trials/current')
req = Net::HTTP::Get.new(uri)
req['Content-Type'] = "application/json"
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}/subscriptions/trials/current", {
method: "GET",
headers: {
"Content-Type": "application/json"
},
})
.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}/subscriptions/trials/current', headers={'content-type': 'application/json'})
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();
let json = client.request(Method::GET, "https://focus.toggl.com/api/organizations/{organization_id}/subscriptions/trials/current".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
Current active trial
| Name | Type | Description |
|---|---|---|
| id | integer | - |
| organization_id | integer | - |
| plan_id | integer | - |
| plan_name | string | - |
| product_handle | string | - |
| toggl_product_name | string | - |
| trial_cancels_at | string | - |
| trial_created_at | string | - |
| trial_deleted_at | string | - |
| trial_ended_at | string | - |
| trial_started_at | string | - |
| trial_type | string | - |
204
No active trial found
400
Invalid request
404
Subscription not found
500
Internal server error
POST Upserts a trial
https://focus.toggl.com/api/organizations/{organization_id}/workspaces/{workspace_id}/subscriptions/upsert-forced-trial
Creates or updates a trial for the organization based on workspace data and Plan import history.
- cURL
- Go
- Ruby
- JavaScript
- Python
- Rust
curl -X POST https://focus.toggl.com/api/organizations/{organization_id}/workspaces/{workspace_id}/subscriptions/upsert-forced-trial \
-H "Content-Type: application/json" \
-d '\{"plan_workspace_id":"integer"\}'
bytes, err := json.Marshal('\{"plan_workspace_id":"integer"\}')
if err != nil {
print(err)
}
req, err := http.NewRequest(http.MethodPost,
"https://focus.toggl.com/api/organizations/{organization_id}/workspaces/{workspace_id}/subscriptions/upsert-forced-trial", bytes.NewBuffer(bytes))
if err != nil {
print(err)
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
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}/workspaces/{workspace_id}/subscriptions/upsert-forced-trial')
req = Net::HTTP::Post.new(uri)
req['Content-Type'] = "application/json"
req.body = \{"plan_workspace_id":"integer"\}.to_json
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}/workspaces/{workspace_id}/subscriptions/upsert-forced-trial", {
method: "POST",
body: \{"plan_workspace_id":"integer"\},
headers: {
"Content-Type": "application/json"
},
})
.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}/workspaces/{workspace_id}/subscriptions/upsert-forced-trial', json=\{"plan_workspace_id":"integer"\}, headers={'content-type': 'application/json'})
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();
let json = client.request(Method::POST, "https://focus.toggl.com/api/organizations/{organization_id}/workspaces/{workspace_id}/subscriptions/upsert-forced-trial".to_string())
.json(&serde_json::json!(\{"plan_workspace_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 |
| workspace_id | integer | true | workspace ID |
Body
| Name | Type | Description |
|---|---|---|
| plan_workspace_id | integer | - |
Response
200
Trial was created or updated
| Name | Type | Description |
|---|---|---|
| id | integer | - |
| organization_id | integer | - |
| plan_id | integer | - |
| plan_name | string | - |
| product_handle | string | - |
| toggl_product_name | string | - |
| trial_cancels_at | string | - |
| trial_created_at | string | - |
| trial_deleted_at | string | - |
| trial_ended_at | string | - |
| trial_started_at | string | - |
| trial_type | string | - |
204
No trial created or updated (existing unchanged trial, paid subscription, or no eligible trial)
400
Invalid request
409
Forced trial already exists or org has active subscription
500
Internal server error