Create a workforce calculation
curl --request POST \
--url https://api.plane.com/v1/workforce/calculations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"plan": "<string>",
"positions": [
{
"positions.job": "<string>",
"positions.location": {},
"positions.location.country": "<string>",
"positions.location.subdivision": "<string>",
"positions.employer": {},
"positions.starts": "<string>",
"positions.ends": "<string>",
"positions.compensation": {},
"positions.compensation.amount": "<string>",
"positions.compensation.currency": "<string>",
"positions.compensation.unit": "<string>",
"positions.compensation.basis": "<string>",
"positions.compensation.frequency": "<string>",
"positions.compensation.source": {}
}
],
"period": {
"period.starts": "<string>",
"period.ends": "<string>",
"period.frequency": "<string>"
},
"currency": "<string>",
"metadata": {}
}
'import requests
url = "https://api.plane.com/v1/workforce/calculations"
payload = {
"plan": "<string>",
"positions": [
{
"positions.job": "<string>",
"positions.location": {},
"positions.location.country": "<string>",
"positions.location.subdivision": "<string>",
"positions.employer": {},
"positions.starts": "<string>",
"positions.ends": "<string>",
"positions.compensation": {},
"positions.compensation.amount": "<string>",
"positions.compensation.currency": "<string>",
"positions.compensation.unit": "<string>",
"positions.compensation.basis": "<string>",
"positions.compensation.frequency": "<string>",
"positions.compensation.source": {}
}
],
"period": {
"period.starts": "<string>",
"period.ends": "<string>",
"period.frequency": "<string>"
},
"currency": "<string>",
"metadata": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
plan: '<string>',
positions: [
{
'positions.job': '<string>',
'positions.location': {},
'positions.location.country': '<string>',
'positions.location.subdivision': '<string>',
'positions.employer': {},
'positions.starts': '<string>',
'positions.ends': '<string>',
'positions.compensation': {},
'positions.compensation.amount': '<string>',
'positions.compensation.currency': '<string>',
'positions.compensation.unit': '<string>',
'positions.compensation.basis': '<string>',
'positions.compensation.frequency': '<string>',
'positions.compensation.source': {}
}
],
period: {
'period.starts': '<string>',
'period.ends': '<string>',
'period.frequency': '<string>'
},
currency: '<string>',
metadata: {}
})
};
fetch('https://api.plane.com/v1/workforce/calculations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.plane.com/v1/workforce/calculations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'plan' => '<string>',
'positions' => [
[
'positions.job' => '<string>',
'positions.location' => [
],
'positions.location.country' => '<string>',
'positions.location.subdivision' => '<string>',
'positions.employer' => [
],
'positions.starts' => '<string>',
'positions.ends' => '<string>',
'positions.compensation' => [
],
'positions.compensation.amount' => '<string>',
'positions.compensation.currency' => '<string>',
'positions.compensation.unit' => '<string>',
'positions.compensation.basis' => '<string>',
'positions.compensation.frequency' => '<string>',
'positions.compensation.source' => [
]
]
],
'period' => [
'period.starts' => '<string>',
'period.ends' => '<string>',
'period.frequency' => '<string>'
],
'currency' => '<string>',
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.plane.com/v1/workforce/calculations"
payload := strings.NewReader("{\n \"plan\": \"<string>\",\n \"positions\": [\n {\n \"positions.job\": \"<string>\",\n \"positions.location\": {},\n \"positions.location.country\": \"<string>\",\n \"positions.location.subdivision\": \"<string>\",\n \"positions.employer\": {},\n \"positions.starts\": \"<string>\",\n \"positions.ends\": \"<string>\",\n \"positions.compensation\": {},\n \"positions.compensation.amount\": \"<string>\",\n \"positions.compensation.currency\": \"<string>\",\n \"positions.compensation.unit\": \"<string>\",\n \"positions.compensation.basis\": \"<string>\",\n \"positions.compensation.frequency\": \"<string>\",\n \"positions.compensation.source\": {}\n }\n ],\n \"period\": {\n \"period.starts\": \"<string>\",\n \"period.ends\": \"<string>\",\n \"period.frequency\": \"<string>\"\n },\n \"currency\": \"<string>\",\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.plane.com/v1/workforce/calculations")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"plan\": \"<string>\",\n \"positions\": [\n {\n \"positions.job\": \"<string>\",\n \"positions.location\": {},\n \"positions.location.country\": \"<string>\",\n \"positions.location.subdivision\": \"<string>\",\n \"positions.employer\": {},\n \"positions.starts\": \"<string>\",\n \"positions.ends\": \"<string>\",\n \"positions.compensation\": {},\n \"positions.compensation.amount\": \"<string>\",\n \"positions.compensation.currency\": \"<string>\",\n \"positions.compensation.unit\": \"<string>\",\n \"positions.compensation.basis\": \"<string>\",\n \"positions.compensation.frequency\": \"<string>\",\n \"positions.compensation.source\": {}\n }\n ],\n \"period\": {\n \"period.starts\": \"<string>\",\n \"period.ends\": \"<string>\",\n \"period.frequency\": \"<string>\"\n },\n \"currency\": \"<string>\",\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.plane.com/v1/workforce/calculations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"plan\": \"<string>\",\n \"positions\": [\n {\n \"positions.job\": \"<string>\",\n \"positions.location\": {},\n \"positions.location.country\": \"<string>\",\n \"positions.location.subdivision\": \"<string>\",\n \"positions.employer\": {},\n \"positions.starts\": \"<string>\",\n \"positions.ends\": \"<string>\",\n \"positions.compensation\": {},\n \"positions.compensation.amount\": \"<string>\",\n \"positions.compensation.currency\": \"<string>\",\n \"positions.compensation.unit\": \"<string>\",\n \"positions.compensation.basis\": \"<string>\",\n \"positions.compensation.frequency\": \"<string>\",\n \"positions.compensation.source\": {}\n }\n ],\n \"period\": {\n \"period.starts\": \"<string>\",\n \"period.ends\": \"<string>\",\n \"period.frequency\": \"<string>\"\n },\n \"currency\": \"<string>\",\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"plan": "wfp_R8mK2pQ9xL4s"
}
{
"id": "wfc_V6nP3qR9tY2m",
"object": "workforce.calculation",
"status": "calculated",
"plan": "wfp_R8mK2pQ9xL4s",
"currency": "USD",
"period": {
"starts": "2026-09-01",
"ends": "2026-10-31",
"frequency": "monthly"
},
"headcount": "1.0",
"cost": {
"total": "26400.00",
"cash": "26400.00",
"accrual": "0.00"
},
"periods": [
{
"period": "2026-09",
"headcount": "1.0",
"cost": "13200.00",
"line_items": []
}
],
"created": "2026-05-27T12:00:00Z"
}
Calculations
Create a workforce calculation
Calculate projected headcount and cost for future positions.
POST
/
v1
/
workforce
/
calculations
Create a workforce calculation
curl --request POST \
--url https://api.plane.com/v1/workforce/calculations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"plan": "<string>",
"positions": [
{
"positions.job": "<string>",
"positions.location": {},
"positions.location.country": "<string>",
"positions.location.subdivision": "<string>",
"positions.employer": {},
"positions.starts": "<string>",
"positions.ends": "<string>",
"positions.compensation": {},
"positions.compensation.amount": "<string>",
"positions.compensation.currency": "<string>",
"positions.compensation.unit": "<string>",
"positions.compensation.basis": "<string>",
"positions.compensation.frequency": "<string>",
"positions.compensation.source": {}
}
],
"period": {
"period.starts": "<string>",
"period.ends": "<string>",
"period.frequency": "<string>"
},
"currency": "<string>",
"metadata": {}
}
'import requests
url = "https://api.plane.com/v1/workforce/calculations"
payload = {
"plan": "<string>",
"positions": [
{
"positions.job": "<string>",
"positions.location": {},
"positions.location.country": "<string>",
"positions.location.subdivision": "<string>",
"positions.employer": {},
"positions.starts": "<string>",
"positions.ends": "<string>",
"positions.compensation": {},
"positions.compensation.amount": "<string>",
"positions.compensation.currency": "<string>",
"positions.compensation.unit": "<string>",
"positions.compensation.basis": "<string>",
"positions.compensation.frequency": "<string>",
"positions.compensation.source": {}
}
],
"period": {
"period.starts": "<string>",
"period.ends": "<string>",
"period.frequency": "<string>"
},
"currency": "<string>",
"metadata": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
plan: '<string>',
positions: [
{
'positions.job': '<string>',
'positions.location': {},
'positions.location.country': '<string>',
'positions.location.subdivision': '<string>',
'positions.employer': {},
'positions.starts': '<string>',
'positions.ends': '<string>',
'positions.compensation': {},
'positions.compensation.amount': '<string>',
'positions.compensation.currency': '<string>',
'positions.compensation.unit': '<string>',
'positions.compensation.basis': '<string>',
'positions.compensation.frequency': '<string>',
'positions.compensation.source': {}
}
],
period: {
'period.starts': '<string>',
'period.ends': '<string>',
'period.frequency': '<string>'
},
currency: '<string>',
metadata: {}
})
};
fetch('https://api.plane.com/v1/workforce/calculations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.plane.com/v1/workforce/calculations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'plan' => '<string>',
'positions' => [
[
'positions.job' => '<string>',
'positions.location' => [
],
'positions.location.country' => '<string>',
'positions.location.subdivision' => '<string>',
'positions.employer' => [
],
'positions.starts' => '<string>',
'positions.ends' => '<string>',
'positions.compensation' => [
],
'positions.compensation.amount' => '<string>',
'positions.compensation.currency' => '<string>',
'positions.compensation.unit' => '<string>',
'positions.compensation.basis' => '<string>',
'positions.compensation.frequency' => '<string>',
'positions.compensation.source' => [
]
]
],
'period' => [
'period.starts' => '<string>',
'period.ends' => '<string>',
'period.frequency' => '<string>'
],
'currency' => '<string>',
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.plane.com/v1/workforce/calculations"
payload := strings.NewReader("{\n \"plan\": \"<string>\",\n \"positions\": [\n {\n \"positions.job\": \"<string>\",\n \"positions.location\": {},\n \"positions.location.country\": \"<string>\",\n \"positions.location.subdivision\": \"<string>\",\n \"positions.employer\": {},\n \"positions.starts\": \"<string>\",\n \"positions.ends\": \"<string>\",\n \"positions.compensation\": {},\n \"positions.compensation.amount\": \"<string>\",\n \"positions.compensation.currency\": \"<string>\",\n \"positions.compensation.unit\": \"<string>\",\n \"positions.compensation.basis\": \"<string>\",\n \"positions.compensation.frequency\": \"<string>\",\n \"positions.compensation.source\": {}\n }\n ],\n \"period\": {\n \"period.starts\": \"<string>\",\n \"period.ends\": \"<string>\",\n \"period.frequency\": \"<string>\"\n },\n \"currency\": \"<string>\",\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.plane.com/v1/workforce/calculations")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"plan\": \"<string>\",\n \"positions\": [\n {\n \"positions.job\": \"<string>\",\n \"positions.location\": {},\n \"positions.location.country\": \"<string>\",\n \"positions.location.subdivision\": \"<string>\",\n \"positions.employer\": {},\n \"positions.starts\": \"<string>\",\n \"positions.ends\": \"<string>\",\n \"positions.compensation\": {},\n \"positions.compensation.amount\": \"<string>\",\n \"positions.compensation.currency\": \"<string>\",\n \"positions.compensation.unit\": \"<string>\",\n \"positions.compensation.basis\": \"<string>\",\n \"positions.compensation.frequency\": \"<string>\",\n \"positions.compensation.source\": {}\n }\n ],\n \"period\": {\n \"period.starts\": \"<string>\",\n \"period.ends\": \"<string>\",\n \"period.frequency\": \"<string>\"\n },\n \"currency\": \"<string>\",\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.plane.com/v1/workforce/calculations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"plan\": \"<string>\",\n \"positions\": [\n {\n \"positions.job\": \"<string>\",\n \"positions.location\": {},\n \"positions.location.country\": \"<string>\",\n \"positions.location.subdivision\": \"<string>\",\n \"positions.employer\": {},\n \"positions.starts\": \"<string>\",\n \"positions.ends\": \"<string>\",\n \"positions.compensation\": {},\n \"positions.compensation.amount\": \"<string>\",\n \"positions.compensation.currency\": \"<string>\",\n \"positions.compensation.unit\": \"<string>\",\n \"positions.compensation.basis\": \"<string>\",\n \"positions.compensation.frequency\": \"<string>\",\n \"positions.compensation.source\": {}\n }\n ],\n \"period\": {\n \"period.starts\": \"<string>\",\n \"period.ends\": \"<string>\",\n \"period.frequency\": \"<string>\"\n },\n \"currency\": \"<string>\",\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"plan": "wfp_R8mK2pQ9xL4s"
}
{
"id": "wfc_V6nP3qR9tY2m",
"object": "workforce.calculation",
"status": "calculated",
"plan": "wfp_R8mK2pQ9xL4s",
"currency": "USD",
"period": {
"starts": "2026-09-01",
"ends": "2026-10-31",
"frequency": "monthly"
},
"headcount": "1.0",
"cost": {
"total": "26400.00",
"cash": "26400.00",
"accrual": "0.00"
},
"periods": [
{
"period": "2026-09",
"headcount": "1.0",
"cost": "13200.00",
"line_items": []
}
],
"created": "2026-05-27T12:00:00Z"
}
Use this endpoint to calculate future workforce cost without creating a worker.
Create a calculation from either a saved workforce plan or inline position
input. Calculations are immutable snapshots.
Parameters
string
Workforce plan ID. When provided, Plane calculates the current positions in
the plan using the plan’s period and currency unless overridden.
array
Inline positions to calculate.
Show child attributes
Show child attributes
string
ID of the job catalog entry for the position.
object
required
Position location.
string
required
Two-letter country code.
string
State, province, or subdivision code.
object
required
Employer model for the position. Supported types are
employee and
contractor.string
required
Position start date.
string
Position end date.
object
required
Compensation used to calculate position cost.
string
required
Compensation amount in decimal format.
string
required
Three-letter ISO currency code.
string
required
Compensation unit, such as
month or year.string
Whether the amount is
gross pay or regular pay. Use gross when the
amount already includes mandatory worker earnings. Use regular when
mandatory worker earnings should be calculated on top.string
Pay frequency, such as
monthly.object
Source for the compensation amount. Use
{ "type": "manual" } for manual inputs.object
string
Three-letter ISO currency code for calculation totals. When omitted, Plane uses
the first position’s compensation currency.
object
Set of key-value pairs attached to the calculation.
Returns
Returns the created Workforce calculation object. Provide eitherplan or positions, but not both.
{
"plan": "wfp_R8mK2pQ9xL4s"
}
{
"id": "wfc_V6nP3qR9tY2m",
"object": "workforce.calculation",
"status": "calculated",
"plan": "wfp_R8mK2pQ9xL4s",
"currency": "USD",
"period": {
"starts": "2026-09-01",
"ends": "2026-10-31",
"frequency": "monthly"
},
"headcount": "1.0",
"cost": {
"total": "26400.00",
"cash": "26400.00",
"accrual": "0.00"
},
"periods": [
{
"period": "2026-09",
"headcount": "1.0",
"cost": "13200.00",
"line_items": []
}
],
"created": "2026-05-27T12:00:00Z"
}
Was this page helpful?
⌘I