Browse docs

Templates API

List, fetch, and create inspection templates. Use the same API key as for Inspections. All endpoints require the Authorization header (Bearer token or Basic auth) when used from an integration.

REST

When to use which endpoint

GoalEndpoint
Get template IDs for inspection import or dropdownsGET /api/templates — returns a light list (id, title, type, status, …).
Get full template: questions in order + logic rules (for import or cloning)GET /api/templates/{id} — replace {id} with a template ID from the list.
Create a new template (sections, questions, conditional rules)POST /api/templates — send createdBy, name, type, and optionally sections, questions, logicRules.

Quick reference

MethodPathDescription
GET/api/templatesList templates (light). Query: publishedOnly=false for drafts.
GET/api/templates/{id}Get one template with sections, questions, and logic rules.
POST/api/templatesCreate a template (body: createdBy, name, type, sections, questions, logicRules).

List templates

Returns templates for your organization. Response is a plain array of template objects (not { templates: [...] }). By default only published templates are returned; use these as templateId in POST /api/inspections. Set publishedOnly=false to include drafts.

Request

GET /api/templates HTTP/1.1
Host: <your-app-host>
Authorization: Bearer <your_api_key>
Accept: application/json

# Optional query: include draft/archived (default is published only)
GET /api/templates?publishedOnly=false

Replace <your-app-host> with your deployment base URL (e.g. https://yourapp.com). Replace <your_api_key> with your Bearer token or use Basic auth.

Query parameters

ParameterDescription
publishedOnlyDefault true. Set to false to include DRAFT/archived templates.

Response (200 OK)

HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "title": "Daily Pump Check",
    "initialTitle": null,
    "type": "ASSET",
    "status": "PUBLISHED",
    "version": 2,
    "isActive": true,
    "assetTypeId": "at_xyz",
    "assetType": { "id": "at_xyz", "name": "Pumps" },
    "organizationId": "org_1",
    "createdAt": "2025-01-15T10:00:00.000Z",
    "updatedAt": "2025-02-01T14:30:00.000Z"
  }
]

Response fields

FieldDescription
idTemplate ID — use as templateId in POST /api/inspections or in GET /api/templates/{id}.
titleTemplate title.
typeASSET or AUDIT. AUDIT inspections require siteId.
statusPUBLISHED or DRAFT. Only published templates can be used for inspection import.
version, assetTypeId, assetTypeMetadata. assetType is { id, name } when set.

Status codes: 200 — success. 401 — missing or invalid API key. 429 — rate limit exceeded.

Get one template (questions + rules)

Returns a single template with sections, questions in order, and logic rules. Use this to build inspection import payloads (you need question ids for answers[].questionId) or to replicate template structure including conditional “show question when…” rules.

Request

GET /api/templates/550e8400-e29b-41d4-a716-446655440000 HTTP/1.1
Host: <your-app-host>
Authorization: Bearer <your_api_key>
Accept: application/json

Replace 550e8400-e29b-41d4-a716-446655440000 with a template id from GET /api/templates.

Response (200 OK)

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "title": "Daily Pump Check",
  "type": "ASSET",
  "status": "PUBLISHED",
  "sections": [
    {
      "id": "sec_1",
      "title": "Safety",
      "position": 0,
      "questions": [
        {
          "id": "q_1",
          "text": "Is the area clear?",
          "required": true,
          "position": 0,
          "responseType": { "id": "rt_1", "name": "Yes/No", "inputType": "SELECT", "uiLabel": "Yes/No" },
          "options": [{ "id": "opt_1", "label": "Yes", "value": "yes", "position": 0 }, { "id": "opt_2", "label": "No", "value": "no", "position": 1 }],
          "logicRules": [
            {
              "id": "rule_1",
              "order": 0,
              "condition": { "type": "equals", "value": "yes" },
              "actionType": "ask_questions",
              "triggeredQuestionId": "q_2",
              "triggeredQuestion": { "id": "q_2", "text": "Describe the issue.", "position": 0 }
            }
          ],
          "triggerRule": null
        },
        {
          "id": "q_2",
          "text": "Describe the issue.",
          "required": false,
          "position": 1,
          "responseType": { "id": "rt_2", "name": "Text", "inputType": "TEXT", "uiLabel": "Text" },
          "options": [],
          "logicRules": [],
          "triggerRule": { "id": "rule_1", "condition": { "type": "equals", "value": "yes" }, "questionId": "q_1", "question": { "id": "q_1", "text": "Is the area clear?", "position": 0 } }
        }
      ]
    }
  ],
  "standaloneQuestions": []
}

logicRules on a question: rules that this question triggers (when its answer matches condition, triggeredQuestion is shown). triggerRule on a question: the rule that causes this question to be shown; triggerRule.question is the source question and triggerRule.condition is the condition.

Response fields (per question)

FieldDescription
idQuestion ID — use as questionId in POST /api/inspections answers[].
text, required, positionLabel, required flag, order.
responseType{ id, name, inputType, uiLabel }.
optionsFor choice questions: [{ id, label, value, position }]. Use value or id in rule conditions and in answers.
logicRulesRules on this question: condition (e.g. { type, value }), actionType, triggeredQuestionId, triggeredQuestion.
triggerRuleIf conditional: condition, questionId, question (source question).

Status codes: 200 — success. 401 — unauthorized. 403 — template belongs to another org. 404 — template not found. 429 — rate limited.

Create template

Creates a new template in your organization. With API key you must send createdBy (a user ID in your org). Template is created in DRAFT status; publish from the app if you need it for inspection import.

Request

POST /api/templates HTTP/1.1
Host: <your-app-host>
Authorization: Bearer <your_api_key>
Content-Type: application/json

{
  "createdBy": "<user_id_from_your_org>",
  "name": "Daily Equipment Check",
  "type": "ASSET",
  "description": "Optional description",
  "assetTypeId": null,
  "sections": [
    {
      "title": "Safety",
      "questions": [
        { "key": "q1", "text": "Is the area clear?", "required": true, "responseTypeId": "<response_type_id>" },
        { "key": "q2", "text": "Describe the issue.", "required": false, "responseTypeId": "<response_type_id>" }
      ]
    }
  ],
  "questions": [],
  "logicRules": [
    { "sourceKey": "q1", "targetKey": "q2", "condition": { "type": "equals", "value": "Yes" }, "actionType": "ask_questions", "order": 0 }
  ]
}

Request body

FieldRequiredDescription
createdByYes (API key)User ID in your organization (e.g. from GET /api/users or your user list).
nameYesTemplate title.
typeYesASSET or AUDIT.
descriptionNoOptional description.
assetTypeIdNoFor ASSET templates, link to an asset type.
sectionsNoArray of { title, description?, questions: [{ key?, text, required?, responseTypeId?, hint? }] }. Use key for questions that participate in logicRules.
questionsNoStandalone questions (same shape; no section).
logicRulesNoArray of { sourceKey, targetKey, condition: { type, value }, actionType?, order? }. See Logic rules below.

Where to get IDs: createdBy — use a user ID from your org (e.g. GET /api/users if available, or from the app). responseTypeId — response types (Yes/No, Text, Number, etc.) are defined in your organization; use the app (e.g. template builder or admin) to see IDs, or omit for optional questions.

Success response (200 OK)

HTTP/1.1 200 OK
Content-Type: application/json

{
  "success": true,
  "message": "Template saved successfully",
  "template": {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "title": "Daily Equipment Check",
    "type": "ASSET",
    "status": "DRAFT",
    "sections": [...],
    "standaloneQuestions": [...]
  }
}

The template object includes the created template with id, sections, and standaloneQuestions. The app UI uses sections only; standaloneQuestions is deprecated.

Validation error (400)

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": "Template name and type are required"
}

# Or when using API key without createdBy:
{
  "error": "createdBy (user ID) is required when using API key. Use a user in your organization."
}

Logic rules (conditional “show question when…”)

Give questions that participate in rules an optional key (e.g. "q1", "q2"). In logicRules, sourceKey is the question whose answer is evaluated; targetKey is the question to show when the condition is met. For choice questions, condition.value should match the option’s value (or option id) as returned by GET /api/templates/{id}.

FieldDescription
sourceKeyKey of the trigger question.
targetKeyKey of the question to show.
condition.typeequals, is_selected, is_not_selected, is_not_equals, is_empty, is_not_empty, is_one_of, is_not_one_of, greater_than, less_than.
condition.valueValue to compare (e.g. option value for choice questions).
actionTypeOptional; default ask_questions.
orderOptional; order when multiple rules apply.

Rules whose sourceKey or targetKey do not match any question key are skipped.

Rate limits

Same as other APIs (per API key). See Error Handling for details.

Error responses

CodeMeaning
400Bad request — missing required fields (e.g. name, type, or createdBy when using API key), or invalid body.
401Unauthorized — missing or invalid API key.
403Forbidden — e.g. template belongs to another organization, or (POST without API key) not an admin.
404Not found — template ID does not exist or not in your org (GET).
429Rate limit exceeded.
500Server error — see response body for details.
Top