Create a form template
curl --request POST \
--url https://api.hellotracks.com/v1/forms/templates \
--header 'API-Key: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"title": "Site check",
"content": [
{
"type": "section",
"name": "Arrival"
},
{
"type": "radio",
"name": "Site clean",
"options": [
"Yes",
"No"
],
"required": true,
"conditionals": [
{
"equalsTo": "No",
"content": [
{
"type": "paragraph",
"name": "What was wrong",
"required": true
}
]
}
]
},
{
"type": "image",
"name": "Photo"
}
]
}
'import requests
url = "https://api.hellotracks.com/v1/forms/templates"
payload = {
"title": "Site check",
"content": [
{
"type": "section",
"name": "Arrival"
},
{
"type": "radio",
"name": "Site clean",
"options": ["Yes", "No"],
"required": True,
"conditionals": [
{
"equalsTo": "No",
"content": [
{
"type": "paragraph",
"name": "What was wrong",
"required": True
}
]
}
]
},
{
"type": "image",
"name": "Photo"
}
]
}
headers = {
"API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
title: 'Site check',
content: [
{type: 'section', name: 'Arrival'},
{
type: 'radio',
name: 'Site clean',
options: ['Yes', 'No'],
required: true,
conditionals: [
{
equalsTo: 'No',
content: [{type: 'paragraph', name: 'What was wrong', required: true}]
}
]
},
{type: 'image', name: 'Photo'}
]
})
};
fetch('https://api.hellotracks.com/v1/forms/templates', 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.hellotracks.com/v1/forms/templates",
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([
'title' => 'Site check',
'content' => [
[
'type' => 'section',
'name' => 'Arrival'
],
[
'type' => 'radio',
'name' => 'Site clean',
'options' => [
'Yes',
'No'
],
'required' => true,
'conditionals' => [
[
'equalsTo' => 'No',
'content' => [
[
'type' => 'paragraph',
'name' => 'What was wrong',
'required' => true
]
]
]
]
],
[
'type' => 'image',
'name' => 'Photo'
]
]
]),
CURLOPT_HTTPHEADER => [
"API-Key: <api-key>",
"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.hellotracks.com/v1/forms/templates"
payload := strings.NewReader("{\n \"title\": \"Site check\",\n \"content\": [\n {\n \"type\": \"section\",\n \"name\": \"Arrival\"\n },\n {\n \"type\": \"radio\",\n \"name\": \"Site clean\",\n \"options\": [\n \"Yes\",\n \"No\"\n ],\n \"required\": true,\n \"conditionals\": [\n {\n \"equalsTo\": \"No\",\n \"content\": [\n {\n \"type\": \"paragraph\",\n \"name\": \"What was wrong\",\n \"required\": true\n }\n ]\n }\n ]\n },\n {\n \"type\": \"image\",\n \"name\": \"Photo\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("API-Key", "<api-key>")
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.hellotracks.com/v1/forms/templates")
.header("API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"Site check\",\n \"content\": [\n {\n \"type\": \"section\",\n \"name\": \"Arrival\"\n },\n {\n \"type\": \"radio\",\n \"name\": \"Site clean\",\n \"options\": [\n \"Yes\",\n \"No\"\n ],\n \"required\": true,\n \"conditionals\": [\n {\n \"equalsTo\": \"No\",\n \"content\": [\n {\n \"type\": \"paragraph\",\n \"name\": \"What was wrong\",\n \"required\": true\n }\n ]\n }\n ]\n },\n {\n \"type\": \"image\",\n \"name\": \"Photo\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.hellotracks.com/v1/forms/templates")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"title\": \"Site check\",\n \"content\": [\n {\n \"type\": \"section\",\n \"name\": \"Arrival\"\n },\n {\n \"type\": \"radio\",\n \"name\": \"Site clean\",\n \"options\": [\n \"Yes\",\n \"No\"\n ],\n \"required\": true,\n \"conditionals\": [\n {\n \"equalsTo\": \"No\",\n \"content\": [\n {\n \"type\": \"paragraph\",\n \"name\": \"What was wrong\",\n \"required\": true\n }\n ]\n }\n ]\n },\n {\n \"type\": \"image\",\n \"name\": \"Photo\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": {
"template": {
"id": "3f2b8c1e-0000-4000-8000-000000000001",
"templateId": "3f2b8c1e-0000-4000-8000-000000000001",
"title": "Site check",
"submissionId": 0,
"submissionUid": "0",
"creatorUid": "a1b2c3",
"createdTs": 1761900000000,
"updatedTs": 1761900000000,
"updaterUid": "a1b2c3",
"status": 0,
"statusText": "active",
"content": {
"id": "3f2b8c1e-0000-4000-8000-000000000001",
"title": "Site check",
"description": "",
"timestamp": 1761900000000,
"content": [
{
"type": "section",
"name": "Arrival",
"options": [],
"value": "",
"required": false,
"conditionals": []
},
{
"type": "radio",
"name": "Site clean",
"options": [
"Yes",
"No"
],
"value": "",
"required": true,
"conditionals": [
{
"equalsTo": "No",
"content": [
{
"type": "paragraph",
"name": "What was wrong",
"options": [],
"value": "",
"required": true
}
]
}
]
},
{
"type": "image",
"name": "Photo",
"options": [],
"value": "",
"required": false,
"conditionals": []
}
]
},
"fieldCount": 3,
"requiredCount": 2
},
"items": [
{
"id": "3f2b8c1e-0000-4000-8000-000000000001",
"templateId": "3f2b8c1e-0000-4000-8000-000000000001",
"title": "Site check",
"submissionId": 0,
"submissionUid": "0",
"creatorUid": "a1b2c3",
"createdTs": 1761900000000,
"updatedTs": 1761900000000,
"updaterUid": "a1b2c3",
"status": 0,
"statusText": "active",
"content": {
"id": "3f2b8c1e-0000-4000-8000-000000000001",
"title": "Site check",
"description": "",
"timestamp": 1761900000000,
"content": [
{
"type": "section",
"name": "Arrival",
"options": [],
"value": "",
"required": false,
"conditionals": []
},
{
"type": "radio",
"name": "Site clean",
"options": [
"Yes",
"No"
],
"value": "",
"required": true,
"conditionals": [
{
"equalsTo": "No",
"content": [
{
"type": "paragraph",
"name": "What was wrong",
"options": [],
"value": "",
"required": true
}
]
}
]
},
{
"type": "image",
"name": "Photo",
"options": [],
"value": "",
"required": false,
"conditionals": []
}
]
},
"fieldCount": 3,
"requiredCount": 2
}
]
},
"error": null,
"meta": {
"path": "/v1/forms/templates",
"method": "POST"
}
}{
"data": null,
"error": {
"code": "invalid_request",
"message": "date must be YYYY-MM-DD"
},
"meta": {
"path": "/jobs",
"method": "GET"
}
}{
"data": null,
"error": {
"code": "invalid_api_key",
"message": "Invalid Hellotracks API key."
},
"meta": {
"path": "/jobs",
"method": "GET"
}
}{
"data": null,
"error": {
"code": "forbidden",
"message": "No permission."
},
"meta": {
"path": "/jobs",
"method": "GET"
}
}{
"data": null,
"error": {
"code": "throttled",
"message": "Too many requests."
},
"meta": {
"path": "/jobs",
"method": "GET"
}
}{
"data": null,
"error": {
"code": "internal_error",
"message": "Hellotracks API is temporarily unavailable."
},
"meta": {
"path": "/jobs",
"method": "GET"
}
}Forms
Create a form template
Creates a form template. Field names must be unique; radio and dropdown need options. Answers 200 with the template and the updated list. Admins, operators and the company key only; workers get 403 permission_denied.
POST
/
forms
/
templates
Create a form template
curl --request POST \
--url https://api.hellotracks.com/v1/forms/templates \
--header 'API-Key: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"title": "Site check",
"content": [
{
"type": "section",
"name": "Arrival"
},
{
"type": "radio",
"name": "Site clean",
"options": [
"Yes",
"No"
],
"required": true,
"conditionals": [
{
"equalsTo": "No",
"content": [
{
"type": "paragraph",
"name": "What was wrong",
"required": true
}
]
}
]
},
{
"type": "image",
"name": "Photo"
}
]
}
'import requests
url = "https://api.hellotracks.com/v1/forms/templates"
payload = {
"title": "Site check",
"content": [
{
"type": "section",
"name": "Arrival"
},
{
"type": "radio",
"name": "Site clean",
"options": ["Yes", "No"],
"required": True,
"conditionals": [
{
"equalsTo": "No",
"content": [
{
"type": "paragraph",
"name": "What was wrong",
"required": True
}
]
}
]
},
{
"type": "image",
"name": "Photo"
}
]
}
headers = {
"API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
title: 'Site check',
content: [
{type: 'section', name: 'Arrival'},
{
type: 'radio',
name: 'Site clean',
options: ['Yes', 'No'],
required: true,
conditionals: [
{
equalsTo: 'No',
content: [{type: 'paragraph', name: 'What was wrong', required: true}]
}
]
},
{type: 'image', name: 'Photo'}
]
})
};
fetch('https://api.hellotracks.com/v1/forms/templates', 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.hellotracks.com/v1/forms/templates",
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([
'title' => 'Site check',
'content' => [
[
'type' => 'section',
'name' => 'Arrival'
],
[
'type' => 'radio',
'name' => 'Site clean',
'options' => [
'Yes',
'No'
],
'required' => true,
'conditionals' => [
[
'equalsTo' => 'No',
'content' => [
[
'type' => 'paragraph',
'name' => 'What was wrong',
'required' => true
]
]
]
]
],
[
'type' => 'image',
'name' => 'Photo'
]
]
]),
CURLOPT_HTTPHEADER => [
"API-Key: <api-key>",
"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.hellotracks.com/v1/forms/templates"
payload := strings.NewReader("{\n \"title\": \"Site check\",\n \"content\": [\n {\n \"type\": \"section\",\n \"name\": \"Arrival\"\n },\n {\n \"type\": \"radio\",\n \"name\": \"Site clean\",\n \"options\": [\n \"Yes\",\n \"No\"\n ],\n \"required\": true,\n \"conditionals\": [\n {\n \"equalsTo\": \"No\",\n \"content\": [\n {\n \"type\": \"paragraph\",\n \"name\": \"What was wrong\",\n \"required\": true\n }\n ]\n }\n ]\n },\n {\n \"type\": \"image\",\n \"name\": \"Photo\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("API-Key", "<api-key>")
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.hellotracks.com/v1/forms/templates")
.header("API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"Site check\",\n \"content\": [\n {\n \"type\": \"section\",\n \"name\": \"Arrival\"\n },\n {\n \"type\": \"radio\",\n \"name\": \"Site clean\",\n \"options\": [\n \"Yes\",\n \"No\"\n ],\n \"required\": true,\n \"conditionals\": [\n {\n \"equalsTo\": \"No\",\n \"content\": [\n {\n \"type\": \"paragraph\",\n \"name\": \"What was wrong\",\n \"required\": true\n }\n ]\n }\n ]\n },\n {\n \"type\": \"image\",\n \"name\": \"Photo\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.hellotracks.com/v1/forms/templates")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"title\": \"Site check\",\n \"content\": [\n {\n \"type\": \"section\",\n \"name\": \"Arrival\"\n },\n {\n \"type\": \"radio\",\n \"name\": \"Site clean\",\n \"options\": [\n \"Yes\",\n \"No\"\n ],\n \"required\": true,\n \"conditionals\": [\n {\n \"equalsTo\": \"No\",\n \"content\": [\n {\n \"type\": \"paragraph\",\n \"name\": \"What was wrong\",\n \"required\": true\n }\n ]\n }\n ]\n },\n {\n \"type\": \"image\",\n \"name\": \"Photo\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": {
"template": {
"id": "3f2b8c1e-0000-4000-8000-000000000001",
"templateId": "3f2b8c1e-0000-4000-8000-000000000001",
"title": "Site check",
"submissionId": 0,
"submissionUid": "0",
"creatorUid": "a1b2c3",
"createdTs": 1761900000000,
"updatedTs": 1761900000000,
"updaterUid": "a1b2c3",
"status": 0,
"statusText": "active",
"content": {
"id": "3f2b8c1e-0000-4000-8000-000000000001",
"title": "Site check",
"description": "",
"timestamp": 1761900000000,
"content": [
{
"type": "section",
"name": "Arrival",
"options": [],
"value": "",
"required": false,
"conditionals": []
},
{
"type": "radio",
"name": "Site clean",
"options": [
"Yes",
"No"
],
"value": "",
"required": true,
"conditionals": [
{
"equalsTo": "No",
"content": [
{
"type": "paragraph",
"name": "What was wrong",
"options": [],
"value": "",
"required": true
}
]
}
]
},
{
"type": "image",
"name": "Photo",
"options": [],
"value": "",
"required": false,
"conditionals": []
}
]
},
"fieldCount": 3,
"requiredCount": 2
},
"items": [
{
"id": "3f2b8c1e-0000-4000-8000-000000000001",
"templateId": "3f2b8c1e-0000-4000-8000-000000000001",
"title": "Site check",
"submissionId": 0,
"submissionUid": "0",
"creatorUid": "a1b2c3",
"createdTs": 1761900000000,
"updatedTs": 1761900000000,
"updaterUid": "a1b2c3",
"status": 0,
"statusText": "active",
"content": {
"id": "3f2b8c1e-0000-4000-8000-000000000001",
"title": "Site check",
"description": "",
"timestamp": 1761900000000,
"content": [
{
"type": "section",
"name": "Arrival",
"options": [],
"value": "",
"required": false,
"conditionals": []
},
{
"type": "radio",
"name": "Site clean",
"options": [
"Yes",
"No"
],
"value": "",
"required": true,
"conditionals": [
{
"equalsTo": "No",
"content": [
{
"type": "paragraph",
"name": "What was wrong",
"options": [],
"value": "",
"required": true
}
]
}
]
},
{
"type": "image",
"name": "Photo",
"options": [],
"value": "",
"required": false,
"conditionals": []
}
]
},
"fieldCount": 3,
"requiredCount": 2
}
]
},
"error": null,
"meta": {
"path": "/v1/forms/templates",
"method": "POST"
}
}{
"data": null,
"error": {
"code": "invalid_request",
"message": "date must be YYYY-MM-DD"
},
"meta": {
"path": "/jobs",
"method": "GET"
}
}{
"data": null,
"error": {
"code": "invalid_api_key",
"message": "Invalid Hellotracks API key."
},
"meta": {
"path": "/jobs",
"method": "GET"
}
}{
"data": null,
"error": {
"code": "forbidden",
"message": "No permission."
},
"meta": {
"path": "/jobs",
"method": "GET"
}
}{
"data": null,
"error": {
"code": "throttled",
"message": "Too many requests."
},
"meta": {
"path": "/jobs",
"method": "GET"
}
}{
"data": null,
"error": {
"code": "internal_error",
"message": "Hellotracks API is temporarily unavailable."
},
"meta": {
"path": "/jobs",
"method": "GET"
}
}Authorizations
Your API key, from More → API & Integrations in the dashboard, or from ht signup / ht auth login.
Body
application/json
content is either a FormContent object (then the top-level title, description and timestamp are ignored) or just the array of fields (then title, description and timestamp are taken from the top level). Required on create. On update, title or description alone change only those. id is accepted but ignored; a new template always gets a new UUID.