Service work types
Work types for Service Orders. Only populated on installs running that module.
Licensed feature
This resource needs the servicePF feature active on the install you are calling. Without that every endpoint here answers 403 with feature_not_licensed - that is a licensing answer, not a permissions one, so check the company's features before the token's scopes.
The object#
| Field | Type | Description |
|---|---|---|
| idread-only | integer | NolaPro id. |
| name | string(50) | The code this resource is keyed by. Matching is case insensitive. |
| color | string(7) | Display colour, hex. |
| defaultlengthminutes | integer | Default duration in minutes. |
| cancel | boolean | True once cancelled. Cancelled rows stay referenced by history. |
| externalid | string(100) | Your own key for this service work types. Scoped to your company. |
| lastchangedateread-only | string | Last modification (lastchangedate). Drives modifiedsince. |
Endpoints#
POST/serviceworktypes/batch
207
Create many.
Always answers 207, one result per item.
Requires scope setup:write.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
| Idempotency-Key | header | string | Makes the write safely retryable. Any unique string per logical operation; a UUID is fine.
The failure this prevents is specific: the request succeeds, the response is lost to a timeout, you retry, and the customer is billed twice. With a key, the retry returns the original response - same status, same body, same id - and creates nothing.
The body is part of the key's identity. Reusing a key with a different body is a bug on your side, not a retry, and answers 409 idempotency_replay rather than silently handing back the old response. Keys are remembered for 24 hours. |
Body array
| Field | Type | Description |
|---|---|---|
| idread-only | integer | NolaPro id. |
| name | string(50) | The code this resource is keyed by. Matching is case insensitive. |
| color | string(7) | Display colour, hex. |
| defaultlengthminutes | integer | Default duration in minutes. |
| cancel | boolean | True once cancelled. Cancelled rows stay referenced by history. |
| externalid | string(100) | Your own key for this service work types. Scoped to your company. |
| lastchangedateread-only | string | Last modification (lastchangedate). Drives modifiedsince. |
curl -X POST \ 'https://acme.nolapro.com/!/api/v2/serviceworktypes/batch' \ -H 'Authorization: Bearer $NP_TOKEN' \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: your-unique-key' \ -d '[ { "id": 2, "name": "Install", "color": "#3366cc", "defaultlengthminutes": 60, "cancel": false } ]'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/serviceworktypes/batch'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => json_encode([ [ 'id' => 2, 'name' => 'Install', 'color' => '#3366cc', 'defaultlengthminutes' => 60, 'cancel' => false, ], ]), ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.post( "https://acme.nolapro.com/!/api/v2/serviceworktypes/batch", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, json=[ { "id": 2, "name": "Install", "color": "#3366cc", "defaultlengthminutes": 60, "cancel": False, }, ], ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/serviceworktypes/batch', { method: 'POST', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, body: JSON.stringify([ { id: 2, name: "Install", color: "#3366cc", defaultlengthminutes: 60, cancel: false, }, ]), } ); const data = await res.json();
using System.Net.Http.Json; var token = Environment.GetEnvironmentVariable("NP_TOKEN"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var body = new[] { new { id = 2, name = "Install", color = "#3366cc", defaultlengthminutes = 60, cancel = false, }, }; var req = new HttpRequestMessage(HttpMethod.Post, "https://acme.nolapro.com/!/api/v2/serviceworktypes/batch") { Content = JsonContent.Create(body), }; req.Headers.Add("Idempotency-Key", "your-unique-key"); var res = await http.SendAsync(req); res.EnsureSuccessStatusCode();
GET/serviceworktypes
200403
List service work types.
Requires scope setup:read.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
| name | query | string | Partial match, case insensitive. |
| cancel | query | string | Defaults to false. Pass true for cancelled only, or any. |
| modifiedsince | query | string | RFC 3339 UTC timestamp. Returns only records changed since then, including cancelled ones - so cancel defaults to any rather than false when this is used. The response carries _meta.synced_through; store it and send it back next time. |
| externalid | query | string | Exact match on your own key. Scoped to your company. |
| include | query | string | Comma-separated extras to embed. Only custom_fields is available: the extra fields this install has defined on the record. Off by default, and an unrecognised value is refused rather than ignored. See Conventions. |
When it fails
| Status | Code | Meaning |
|---|---|---|
| 403 | insufficient_scope | Token lacks serviceworktypes:read. |
curl \ 'https://acme.nolapro.com/!/api/v2/serviceworktypes' \ -H 'Authorization: Bearer $NP_TOKEN'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/serviceworktypes'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.get( "https://acme.nolapro.com/!/api/v2/serviceworktypes", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/serviceworktypes', { method: 'GET', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, } ); const data = await res.json();
using System.Net.Http.Json; var token = Environment.GetEnvironmentVariable("NP_TOKEN"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var res = await http.GetAsync( "https://acme.nolapro.com/!/api/v2/serviceworktypes"); res.EnsureSuccessStatusCode();
POST/serviceworktypes
201400409
Create.
Requires scope setup:write.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
| Idempotency-Key | header | string | Makes the write safely retryable. Any unique string per logical operation; a UUID is fine.
The failure this prevents is specific: the request succeeds, the response is lost to a timeout, you retry, and the customer is billed twice. With a key, the retry returns the original response - same status, same body, same id - and creates nothing.
The body is part of the key's identity. Reusing a key with a different body is a bug on your side, not a retry, and answers 409 idempotency_replay rather than silently handing back the old response. Keys are remembered for 24 hours. |
Body
| Field | Type | Description |
|---|---|---|
| idread-only | integer | NolaPro id. |
| name | string(50) | The code this resource is keyed by. Matching is case insensitive. |
| color | string(7) | Display colour, hex. |
| defaultlengthminutes | integer | Default duration in minutes. |
| cancel | boolean | True once cancelled. Cancelled rows stay referenced by history. |
| externalid | string(100) | Your own key for this service work types. Scoped to your company. |
| lastchangedateread-only | string | Last modification (lastchangedate). Drives modifiedsince. |
When it fails
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | A required field was missing or invalid. |
| 409 | duplicate | That code is already in use. |
curl -X POST \ 'https://acme.nolapro.com/!/api/v2/serviceworktypes' \ -H 'Authorization: Bearer $NP_TOKEN' \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: your-unique-key' \ -d '{ "id": 2, "name": "Install", "color": "#3366cc", "defaultlengthminutes": 60, "cancel": false }'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/serviceworktypes'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => json_encode([ 'id' => 2, 'name' => 'Install', 'color' => '#3366cc', 'defaultlengthminutes' => 60, 'cancel' => false, ]), ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.post( "https://acme.nolapro.com/!/api/v2/serviceworktypes", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, json={ "id": 2, "name": "Install", "color": "#3366cc", "defaultlengthminutes": 60, "cancel": False, }, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/serviceworktypes', { method: 'POST', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, body: JSON.stringify({ id: 2, name: "Install", color: "#3366cc", defaultlengthminutes: 60, cancel: false, }), } ); const data = await res.json();
using System.Net.Http.Json; var token = Environment.GetEnvironmentVariable("NP_TOKEN"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var body = new { id = 2, name = "Install", color = "#3366cc", defaultlengthminutes = 60, cancel = false, }; var req = new HttpRequestMessage(HttpMethod.Post, "https://acme.nolapro.com/!/api/v2/serviceworktypes") { Content = JsonContent.Create(body), }; req.Headers.Add("Idempotency-Key", "your-unique-key"); var res = await http.SendAsync(req); res.EnsureSuccessStatusCode();
Response 201
{
"id": 2,
"name": "Install",
"color": "#3366cc",
"defaultlengthminutes": 60,
"cancel": false
}
GET/serviceworktypes/{id}
200404
Retrieve one record.
Requires scope setup:read.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
| idrequired | path | integer | The record id. |
| include | query | string | Comma-separated extras to embed. Only custom_fields is available: the extra fields this install has defined on the record. Off by default, and an unrecognised value is refused rather than ignored. See Conventions. |
When it fails
| Status | Code | Meaning |
|---|---|---|
| 404 | not_found | No record with that id. |
curl \ 'https://acme.nolapro.com/!/api/v2/serviceworktypes/104' \ -H 'Authorization: Bearer $NP_TOKEN'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/serviceworktypes/104'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.get( "https://acme.nolapro.com/!/api/v2/serviceworktypes/104", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/serviceworktypes/104', { method: 'GET', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, } ); const data = await res.json();
using System.Net.Http.Json; var token = Environment.GetEnvironmentVariable("NP_TOKEN"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var res = await http.GetAsync( "https://acme.nolapro.com/!/api/v2/serviceworktypes/104"); res.EnsureSuccessStatusCode();
Response 200
{
"id": 2,
"name": "Install",
"color": "#3366cc",
"defaultlengthminutes": 60,
"cancel": false
}
PATCH/serviceworktypes/{id}
200404409
Update.
Requires scope setup:write.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
| idrequired | path | integer | The record id. |
| Idempotency-Key | header | string | Makes the write safely retryable. Any unique string per logical operation; a UUID is fine.
The failure this prevents is specific: the request succeeds, the response is lost to a timeout, you retry, and the customer is billed twice. With a key, the retry returns the original response - same status, same body, same id - and creates nothing.
The body is part of the key's identity. Reusing a key with a different body is a bug on your side, not a retry, and answers 409 idempotency_replay rather than silently handing back the old response. Keys are remembered for 24 hours. |
Body
| Field | Type | Description |
|---|---|---|
| idread-only | integer | NolaPro id. |
| name | string(50) | The code this resource is keyed by. Matching is case insensitive. |
| color | string(7) | Display colour, hex. |
| defaultlengthminutes | integer | Default duration in minutes. |
| cancel | boolean | True once cancelled. Cancelled rows stay referenced by history. |
| externalid | string(100) | Your own key for this service work types. Scoped to your company. |
| lastchangedateread-only | string | Last modification (lastchangedate). Drives modifiedsince. |
When it fails
| Status | Code | Meaning |
|---|---|---|
| 404 | not_found | No record with that id. |
| 409 | stale_record | If-Match did not match. |
curl -X PATCH \ 'https://acme.nolapro.com/!/api/v2/serviceworktypes/104' \ -H 'Authorization: Bearer $NP_TOKEN' \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: your-unique-key' \ -d '{ "id": 2, "name": "Install", "color": "#3366cc", "defaultlengthminutes": 60, "cancel": false }'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/serviceworktypes/104'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'PATCH', CURLOPT_POSTFIELDS => json_encode([ 'id' => 2, 'name' => 'Install', 'color' => '#3366cc', 'defaultlengthminutes' => 60, 'cancel' => false, ]), ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.patch( "https://acme.nolapro.com/!/api/v2/serviceworktypes/104", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, json={ "id": 2, "name": "Install", "color": "#3366cc", "defaultlengthminutes": 60, "cancel": False, }, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/serviceworktypes/104', { method: 'PATCH', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, body: JSON.stringify({ id: 2, name: "Install", color: "#3366cc", defaultlengthminutes: 60, cancel: false, }), } ); const data = await res.json();
using System.Net.Http.Json; var token = Environment.GetEnvironmentVariable("NP_TOKEN"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var body = new { id = 2, name = "Install", color = "#3366cc", defaultlengthminutes = 60, cancel = false, }; var req = new HttpRequestMessage(HttpMethod.Patch, "https://acme.nolapro.com/!/api/v2/serviceworktypes/104") { Content = JsonContent.Create(body), }; req.Headers.Add("Idempotency-Key", "your-unique-key"); var res = await http.SendAsync(req); res.EnsureSuccessStatusCode();
Response 200
{
"id": 2,
"name": "Install",
"color": "#3366cc",
"defaultlengthminutes": 60,
"cancel": false
}
DELETE/serviceworktypes/{id}
200403404
Cancel.
Sets the cancel flag. Nothing is removed.
Requires scope setup:cancel.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
| idrequired | path | integer | The record id. |
| Idempotency-Key | header | string | Makes the write safely retryable. Any unique string per logical operation; a UUID is fine.
The failure this prevents is specific: the request succeeds, the response is lost to a timeout, you retry, and the customer is billed twice. With a key, the retry returns the original response - same status, same body, same id - and creates nothing.
The body is part of the key's identity. Reusing a key with a different body is a bug on your side, not a retry, and answers 409 idempotency_replay rather than silently handing back the old response. Keys are remembered for 24 hours. |
When it fails
| Status | Code | Meaning |
|---|---|---|
| 403 | insufficient_scope | Needs serviceworktypes:cancel. |
| 404 | not_found | No record with that id. |
curl -X DELETE \ 'https://acme.nolapro.com/!/api/v2/serviceworktypes/104' \ -H 'Authorization: Bearer $NP_TOKEN'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/serviceworktypes/104'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'DELETE', ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.delete( "https://acme.nolapro.com/!/api/v2/serviceworktypes/104", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/serviceworktypes/104', { method: 'DELETE', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, } ); const data = await res.json();
using System.Net.Http.Json; var token = Environment.GetEnvironmentVariable("NP_TOKEN"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var req = new HttpRequestMessage(HttpMethod.Delete, "https://acme.nolapro.com/!/api/v2/serviceworktypes/104"); var res = await http.SendAsync(req); res.EnsureSuccessStatusCode();
Response 200
{
"id": 2,
"name": "Install",
"color": "#3366cc",
"defaultlengthminutes": 60,
"cancel": false
}
Countries →
Countries, with the number formatting NolaPro uses for each. The formatting columns are worth reading if you display amounts - they explain why a total renders differently per country.
Zones →
States and provinces. Static reference data - no writes, no cancel flag, no external ids. Its identifier is
zone_id, because that is what the column is called.