curl --request POST \
--url https://api.ctrl-hub.com/v3/cost-lines \
--header 'Content-Type: application/vnd.api+json' \
--header 'X-Session-Token: <api-key>' \
--data '
{
"data": {
"type": "<string>",
"attributes": {
"quantity": 123,
"line_type": "actual",
"work_date": "2023-12-25",
"description": "<string>",
"margin_override": {
"type": "percentage",
"percentage": 1500
},
"rate": {
"amount": 45000,
"currency": "GBP"
}
},
"relationships": {
"organisation": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
},
"cost_sheet": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
}
}
}
}
'import requests
url = "https://api.ctrl-hub.com/v3/cost-lines"
payload = { "data": {
"type": "<string>",
"attributes": {
"quantity": 123,
"line_type": "actual",
"work_date": "2023-12-25",
"description": "<string>",
"margin_override": {
"type": "percentage",
"percentage": 1500
},
"rate": {
"amount": 45000,
"currency": "GBP"
}
},
"relationships": {
"organisation": { "data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
} },
"cost_sheet": { "data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
} }
}
} }
headers = {
"X-Session-Token": "<api-key>",
"Content-Type": "application/vnd.api+json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Session-Token': '<api-key>', 'Content-Type': 'application/vnd.api+json'},
body: JSON.stringify({
data: {
type: '<string>',
attributes: {
quantity: 123,
line_type: 'actual',
work_date: '2023-12-25',
description: '<string>',
margin_override: {type: 'percentage', percentage: 1500},
rate: {amount: 45000, currency: 'GBP'}
},
relationships: {
organisation: {data: {id: '3c90c3cc-0d44-4b50-8888-8dd25736052a', type: '<string>'}},
cost_sheet: {data: {id: '3c90c3cc-0d44-4b50-8888-8dd25736052a', type: '<string>'}}
}
}
})
};
fetch('https://api.ctrl-hub.com/v3/cost-lines', 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.ctrl-hub.com/v3/cost-lines",
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([
'data' => [
'type' => '<string>',
'attributes' => [
'quantity' => 123,
'line_type' => 'actual',
'work_date' => '2023-12-25',
'description' => '<string>',
'margin_override' => [
'type' => 'percentage',
'percentage' => 1500
],
'rate' => [
'amount' => 45000,
'currency' => 'GBP'
]
],
'relationships' => [
'organisation' => [
'data' => [
'id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'type' => '<string>'
]
],
'cost_sheet' => [
'data' => [
'id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'type' => '<string>'
]
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/vnd.api+json",
"X-Session-Token: <api-key>"
],
]);
$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.ctrl-hub.com/v3/cost-lines"
payload := strings.NewReader("{\n \"data\": {\n \"type\": \"<string>\",\n \"attributes\": {\n \"quantity\": 123,\n \"line_type\": \"actual\",\n \"work_date\": \"2023-12-25\",\n \"description\": \"<string>\",\n \"margin_override\": {\n \"type\": \"percentage\",\n \"percentage\": 1500\n },\n \"rate\": {\n \"amount\": 45000,\n \"currency\": \"GBP\"\n }\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"<string>\"\n }\n },\n \"cost_sheet\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"<string>\"\n }\n }\n }\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Session-Token", "<api-key>")
req.Header.Add("Content-Type", "application/vnd.api+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.ctrl-hub.com/v3/cost-lines")
.header("X-Session-Token", "<api-key>")
.header("Content-Type", "application/vnd.api+json")
.body("{\n \"data\": {\n \"type\": \"<string>\",\n \"attributes\": {\n \"quantity\": 123,\n \"line_type\": \"actual\",\n \"work_date\": \"2023-12-25\",\n \"description\": \"<string>\",\n \"margin_override\": {\n \"type\": \"percentage\",\n \"percentage\": 1500\n },\n \"rate\": {\n \"amount\": 45000,\n \"currency\": \"GBP\"\n }\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"<string>\"\n }\n },\n \"cost_sheet\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"<string>\"\n }\n }\n }\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ctrl-hub.com/v3/cost-lines")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Session-Token"] = '<api-key>'
request["Content-Type"] = 'application/vnd.api+json'
request.body = "{\n \"data\": {\n \"type\": \"<string>\",\n \"attributes\": {\n \"quantity\": 123,\n \"line_type\": \"actual\",\n \"work_date\": \"2023-12-25\",\n \"description\": \"<string>\",\n \"margin_override\": {\n \"type\": \"percentage\",\n \"percentage\": 1500\n },\n \"rate\": {\n \"amount\": 45000,\n \"currency\": \"GBP\"\n }\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"<string>\"\n }\n },\n \"cost_sheet\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"<string>\"\n }\n }\n }\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>",
"attributes": {
"line_type": "actual",
"quantity": 123,
"work_date": "2023-12-25",
"rate": {
"amount": 123,
"currency": "<string>"
},
"amount": {
"amount": 123,
"currency": "<string>"
},
"margin": {
"percentage": 1,
"fixed": {
"amount": 123,
"currency": "<string>"
}
},
"charge": {
"amount": 123,
"currency": "<string>"
},
"margin_override": {
"percentage": 1,
"fixed": {
"amount": 123,
"currency": "<string>"
}
},
"margin_source": "override",
"profit": {
"amount": 123,
"currency": "<string>"
},
"cost_item_snapshot": {
"code": "<string>",
"name": "<string>",
"description": "<string>",
"unit": "<string>",
"margin": {
"percentage": 1,
"fixed": {
"amount": 123,
"currency": "<string>"
}
}
},
"description": "<string>",
"cost_kit": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"code": "<string>",
"name": "<string>"
},
"cost_kit_application_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
},
"meta": {
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
},
"relationships": {
"organisation": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
},
"cost_sheet": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
},
"cost_item": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
},
"cost_item_version": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
}
}
},
"jsonapi": {
"version": "<string>"
},
"included": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>",
"attributes": {
"name": "<string>",
"slug": "<string>",
"sandbox": true,
"description": "<string>",
"settings": {
"teams": {
"customer_representatives": [
"3c90c3cc-0d44-4b50-8888-8dd25736052a"
]
}
}
},
"meta": {
"v3": true,
"status": "active",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"features": [
{
"name": "<string>",
"enabled": true,
"limit": 123
}
]
},
"relationships": {
"users": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
]
},
"service_accounts": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
]
},
"groups": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
]
},
"teams": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
]
},
"nomenclature": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
}
}
}
]
}{
"id": "98ca4a78-b66f-4234-9719-aaf832ee6669",
"status": "400",
"title": "A validation error was encountered",
"source": {
"parameter": "include"
},
"meta": {
"resource": "wrong_value"
}
}{
"id": "05fc9c8d-73b9-4697-9337-57f7a567a48f",
"status": "401",
"title": "You are not authorised to access this resource",
"detail": "In order to access this resource, you need the 'admin' role.",
"code": "AUTH.001"
}{
"id": "7b4c8f12-3e9a-4d5b-8c6f-1a2b3c4d5e6f",
"status": "404",
"title": "Resource not found",
"detail": "The requested resource could not be found or does not exist.",
"code": "NOT_FOUND.001"
}{
"id": "8e2f9a34-b5c6-4d7e-9f8a-2b3c4d5e6f7g",
"status": "409",
"title": "Conflict",
"detail": "The request conflicts with the current state of the resource.",
"code": "CONFLICT.001"
}{
"id": "fe9d9a69-f0a7-4fdc-bb2c-176027f316c5",
"status": "500",
"title": "Internal Server Error",
"detail": "An unexpected error occurred on the server."
}Create a cost line
Add a costed line to a cost sheet. The rate is resolved by the server from the
cost item’s register version in force on work_date, and the resolved rate,
the line amount and the version reference are all persisted as a snapshot —
revising the rate later never changes an existing line.
The request will fail with a 400 Bad Request if the cost item has no rate in
force on work_date.
curl --request POST \
--url https://api.ctrl-hub.com/v3/cost-lines \
--header 'Content-Type: application/vnd.api+json' \
--header 'X-Session-Token: <api-key>' \
--data '
{
"data": {
"type": "<string>",
"attributes": {
"quantity": 123,
"line_type": "actual",
"work_date": "2023-12-25",
"description": "<string>",
"margin_override": {
"type": "percentage",
"percentage": 1500
},
"rate": {
"amount": 45000,
"currency": "GBP"
}
},
"relationships": {
"organisation": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
},
"cost_sheet": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
}
}
}
}
'import requests
url = "https://api.ctrl-hub.com/v3/cost-lines"
payload = { "data": {
"type": "<string>",
"attributes": {
"quantity": 123,
"line_type": "actual",
"work_date": "2023-12-25",
"description": "<string>",
"margin_override": {
"type": "percentage",
"percentage": 1500
},
"rate": {
"amount": 45000,
"currency": "GBP"
}
},
"relationships": {
"organisation": { "data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
} },
"cost_sheet": { "data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
} }
}
} }
headers = {
"X-Session-Token": "<api-key>",
"Content-Type": "application/vnd.api+json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Session-Token': '<api-key>', 'Content-Type': 'application/vnd.api+json'},
body: JSON.stringify({
data: {
type: '<string>',
attributes: {
quantity: 123,
line_type: 'actual',
work_date: '2023-12-25',
description: '<string>',
margin_override: {type: 'percentage', percentage: 1500},
rate: {amount: 45000, currency: 'GBP'}
},
relationships: {
organisation: {data: {id: '3c90c3cc-0d44-4b50-8888-8dd25736052a', type: '<string>'}},
cost_sheet: {data: {id: '3c90c3cc-0d44-4b50-8888-8dd25736052a', type: '<string>'}}
}
}
})
};
fetch('https://api.ctrl-hub.com/v3/cost-lines', 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.ctrl-hub.com/v3/cost-lines",
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([
'data' => [
'type' => '<string>',
'attributes' => [
'quantity' => 123,
'line_type' => 'actual',
'work_date' => '2023-12-25',
'description' => '<string>',
'margin_override' => [
'type' => 'percentage',
'percentage' => 1500
],
'rate' => [
'amount' => 45000,
'currency' => 'GBP'
]
],
'relationships' => [
'organisation' => [
'data' => [
'id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'type' => '<string>'
]
],
'cost_sheet' => [
'data' => [
'id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'type' => '<string>'
]
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/vnd.api+json",
"X-Session-Token: <api-key>"
],
]);
$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.ctrl-hub.com/v3/cost-lines"
payload := strings.NewReader("{\n \"data\": {\n \"type\": \"<string>\",\n \"attributes\": {\n \"quantity\": 123,\n \"line_type\": \"actual\",\n \"work_date\": \"2023-12-25\",\n \"description\": \"<string>\",\n \"margin_override\": {\n \"type\": \"percentage\",\n \"percentage\": 1500\n },\n \"rate\": {\n \"amount\": 45000,\n \"currency\": \"GBP\"\n }\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"<string>\"\n }\n },\n \"cost_sheet\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"<string>\"\n }\n }\n }\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Session-Token", "<api-key>")
req.Header.Add("Content-Type", "application/vnd.api+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.ctrl-hub.com/v3/cost-lines")
.header("X-Session-Token", "<api-key>")
.header("Content-Type", "application/vnd.api+json")
.body("{\n \"data\": {\n \"type\": \"<string>\",\n \"attributes\": {\n \"quantity\": 123,\n \"line_type\": \"actual\",\n \"work_date\": \"2023-12-25\",\n \"description\": \"<string>\",\n \"margin_override\": {\n \"type\": \"percentage\",\n \"percentage\": 1500\n },\n \"rate\": {\n \"amount\": 45000,\n \"currency\": \"GBP\"\n }\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"<string>\"\n }\n },\n \"cost_sheet\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"<string>\"\n }\n }\n }\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ctrl-hub.com/v3/cost-lines")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Session-Token"] = '<api-key>'
request["Content-Type"] = 'application/vnd.api+json'
request.body = "{\n \"data\": {\n \"type\": \"<string>\",\n \"attributes\": {\n \"quantity\": 123,\n \"line_type\": \"actual\",\n \"work_date\": \"2023-12-25\",\n \"description\": \"<string>\",\n \"margin_override\": {\n \"type\": \"percentage\",\n \"percentage\": 1500\n },\n \"rate\": {\n \"amount\": 45000,\n \"currency\": \"GBP\"\n }\n },\n \"relationships\": {\n \"organisation\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"<string>\"\n }\n },\n \"cost_sheet\": {\n \"data\": {\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"type\": \"<string>\"\n }\n }\n }\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>",
"attributes": {
"line_type": "actual",
"quantity": 123,
"work_date": "2023-12-25",
"rate": {
"amount": 123,
"currency": "<string>"
},
"amount": {
"amount": 123,
"currency": "<string>"
},
"margin": {
"percentage": 1,
"fixed": {
"amount": 123,
"currency": "<string>"
}
},
"charge": {
"amount": 123,
"currency": "<string>"
},
"margin_override": {
"percentage": 1,
"fixed": {
"amount": 123,
"currency": "<string>"
}
},
"margin_source": "override",
"profit": {
"amount": 123,
"currency": "<string>"
},
"cost_item_snapshot": {
"code": "<string>",
"name": "<string>",
"description": "<string>",
"unit": "<string>",
"margin": {
"percentage": 1,
"fixed": {
"amount": 123,
"currency": "<string>"
}
}
},
"description": "<string>",
"cost_kit": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"code": "<string>",
"name": "<string>"
},
"cost_kit_application_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
},
"meta": {
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
},
"relationships": {
"organisation": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
},
"cost_sheet": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
},
"cost_item": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
},
"cost_item_version": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
}
}
},
"jsonapi": {
"version": "<string>"
},
"included": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>",
"attributes": {
"name": "<string>",
"slug": "<string>",
"sandbox": true,
"description": "<string>",
"settings": {
"teams": {
"customer_representatives": [
"3c90c3cc-0d44-4b50-8888-8dd25736052a"
]
}
}
},
"meta": {
"v3": true,
"status": "active",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"features": [
{
"name": "<string>",
"enabled": true,
"limit": 123
}
]
},
"relationships": {
"users": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
]
},
"service_accounts": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
]
},
"groups": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
]
},
"teams": {
"data": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
]
},
"nomenclature": {
"data": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "<string>"
}
}
}
}
]
}{
"id": "98ca4a78-b66f-4234-9719-aaf832ee6669",
"status": "400",
"title": "A validation error was encountered",
"source": {
"parameter": "include"
},
"meta": {
"resource": "wrong_value"
}
}{
"id": "05fc9c8d-73b9-4697-9337-57f7a567a48f",
"status": "401",
"title": "You are not authorised to access this resource",
"detail": "In order to access this resource, you need the 'admin' role.",
"code": "AUTH.001"
}{
"id": "7b4c8f12-3e9a-4d5b-8c6f-1a2b3c4d5e6f",
"status": "404",
"title": "Resource not found",
"detail": "The requested resource could not be found or does not exist.",
"code": "NOT_FOUND.001"
}{
"id": "8e2f9a34-b5c6-4d7e-9f8a-2b3c4d5e6f7g",
"status": "409",
"title": "Conflict",
"detail": "The request conflicts with the current state of the resource.",
"code": "CONFLICT.001"
}{
"id": "fe9d9a69-f0a7-4fdc-bb2c-176027f316c5",
"status": "500",
"title": "Internal Server Error",
"detail": "An unexpected error occurred on the server."
}Authorizations
Session token for authentication.
Body
The cost line to create. The line amount, the charge and the profit are always worked out by the server from the rate, the quantity and the margin — none of them can be sent by the client.
There are three valid shapes, and the one rule behind them is that a line may supply its own rate:
- A rate code, priced from the register. Send
cost_itemand norate. The server resolves the rate from the register version in force onwork_date, records that version ascost_item_version, and copies the rate code intocost_item_snapshot. If no version coverswork_datethe request is refused withCH.004.208. - A rate code, priced on this job. Send
cost_itemandrate. The register is not consulted for a version at all, socost_item_versioncomes back null and a rate code carrying no versions is perfectly usable — the code, name and category are still governed by the register, and the price is this job's.cost_item_snapshotmust not be sent; the server copies it. - Ad hoc. Send
rateandcost_item_snapshot, and nocost_item. A cost with no rate code behind it: the client supplies both the price and the description that gives it meaning. Both are required, and so iscost_item_snapshot.categorywithin it — a line nothing can attribute would break the roll-up's category split.
Anything else is refused with CH.004.215.
Whichever shape it is, the price is frozen the moment the line is written. Revising the register afterwards changes what future work costs and leaves recorded work exactly as recorded.
margin_override works the same way in all three: it pins what this particular
line sells at, and the charge it produces is still worked out by the server.
Show child attributes
Show child attributes
Response
An individual cost line.
JSON API response object
A cost line — one costed entry on a cost sheet: a quantity of a rate code, priced at the rate that was in force on the day the work was done.
The pricing is a snapshot, on both sides. rate and amount are resolved
once, on write, from the register version in force on work_date, and that
version is referenced by the cost_item_version relationship. margin and
charge — what the line sells for — are frozen at the same moment. None of
them are ever recomputed: revising a rate or a margin in the register changes
what future lines cost and sell for, and leaves every existing line exactly as
it was recorded.
This resource carries monetary values and is permissioned separately from the cost sheet it belongs to.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Related resources that can be included when a cost line is returned.
cost-items and cost-item-versions are both optional on a line, so asking
for either simply yields nothing for the lines that have none — an ad-hoc line
has no rate code, and a line priced on the job has no register version behind
its rate. Neither is an error, and a request for both across a mixed collection
comes back with whatever exists.
An organisation
- Option 1
- Option 2
- Option 3
- Option 4
Show child attributes
Show child attributes