This guide will review updating an Appointments questions using our API.

When can Appointment be updated?

Appointments must have a Status of Assigned/Completed/Audit Failed.

When an Appointment has progressed to an Audited status to protect the Audits integrity only Failed sub status can be changed.

Appointment with Submissions or with RCTI Invoices finalized are locked from changes to protect their integrity.

The update API will return an error response if appointment has an invalid status.

NOTE: The update endpoint will change the status of the Appointment to ``Completed-Partial` and the Certificates and Products are re-calculated using the new answers.

Overview of Endpoints

These are endpoints used in this guide:

  1. To view existing answer of an Appointment GET /{instance}/appointments/{appointment_id}/answers Download Appointments Answers

  2. To save the answers of an Appointment POST /{instance}/appointments/{appointment_id}/questions Endpoint Save Appointment Answers

  3. Data Dictionary for Question and Answers GET /{instance}/questions/{question_id} and GET /{instance}/questions/{question_id}/answers Data Dictionary Question and Answers

The endpoint POST /{instance}/appointments/{appointment_id}/questions will DELETE all existing answers from the Appointment and replace with those provided.

When changing an existing appointment we recommend the use of the endpoint GET /{instance}/appointments/{appointment_id}/answers to load existing answers make the changes to the data structure and then use the endpoint POST /{instance}/appointments/{appointment_id}/questions to save the changes.

If updates are made to choice fields the dictionary endpoints can be used to fetch the right answerId (detailed further in this guide).

Question Answer Data Structure

Both endpoints GET /{instance}/appointments/{appointment_id}/answers and POST /{instance}/appointments/{appointment_id}/questions have same data-structure below.

{
  "appointmentId": 0,
  "blockAnswers": [
    {
      "questionBlockTypeId": 0,
      "blocks": [
        {
          "answers": [
            {
              "questionId": 0,
              "answerValue": "string"
            }
          ]
        }
      ]
    }
  ],
  "answers": [
    {
      "questionId": 0,
      "answerValue": "string"
    }
  ]
}

Top level strut.

{
  "appointmentId": 0,
  "blockAnswers": []
  "answers": []
}

appointmentId is integer and match the appointment in url of endpoint.

blockAnswers is array for question block questions.

answers is an array of non-block question answers.

If a block question is used under answers a validation error will be returned.

Answer strut.

{
      "questionId": 0,
      "answerValue": "string"
}

questionId is required field and must be an integer while answerValue is expected to be a string.

The Following question types are not supported:

  1. Image - Derived from Files uploaded with file category which matches the question.
  2. Check Box Groups - Checkbox Options which are saved not the group
  3. Dummy Text - Display only

The value of answerValue changes based on the Question Type:

Question Type Expected Value
Text Question String less than 4000 characters with answer
Text Area Question String less than 4000 characters with answer
Quantity Question Stringified integer e.g “answerValue”: “3”
Number Question Stringified Number e.g “answerValue”: “3.78”
Barcodes/Serial Numbers String less than 4000 characters each barcode split by and End of Line (EOL) character”
Image Question Not supported
Dummy Text Not supported
Checkbox Groups Not supported
Checkbox Options string of ‘Yes’ if checked and ‘No’ if unchecked or empty string
Select Stringified integer the answerId e.g “answerValue”: “4523”
Radio Stringified integer the answerId e.g “answerValue”: “4523”
Fieldworker Stringified integer the answerId e.g “answerValue”: “4523” do not use the fieldworkerId or name
Product Stringified integer the answerId e.g “answerValue”: “4523” do not use the productId or name
Date or Time string with date or time in required format

Choice Field Question Types like Question types like Radio,Select,Product and Fieldworker use an answerId as their value. The question dictionary endpoints can be used to lookup both the question type and answers.

Block Type strut

{
 "questionBlockTypeId": 0,
      "blocks": [
        {
          "answers": []
        },
        {
          "answers": []
        },
        {
          "answers": []
        }
      ]
}

questionBlockTypeId integer and question block type.

blocks array contain data for each area.

answers array of answers for this block only.

Using the Dictionary Endpoints.

Data Dictionary for Question and Answers GET /{instance}/questions/{question_id} and GET /{instance}/questions/{question_id}/answers

Example Non Block Text Question

To lookup this question, using request like:

curl -X GET "https://asap-api.dataforce.com.au/DATAFORCE_ESS/questions/1247" -H "accept: application/json" -H "Authorization: Bearer xxxxxx"

Return a response like:

{
  "questionId": 1247,
  "question": "Customers Average energy price (cents per KWh)",
  "type": "Appointment",
  "fieldType": "Number",
  "checkboxId": 0,
  "dataCategoryId": 0,
  "dataCategory": "",
  "sortOrder": 20,
  "mandatory": true,
  "category": "Standard",
  "customerType": "",
  "createdDate": "2016-09-19T14:07:48+10:00",
  "questionBlockTypeId": 0,
  "questionBlockTypeName": "",
  "parentQuestion": [],
  "workType": [
    4,
    7,
    13
  ],
  "agent": [],
  "calculationZone": [],
  "fieldworkerAbility": []
}

Look for the property fieldType see that in this example it is Number, this means that no choice answers.

If look up a non-block Choice question

Non Block Choice Field Question

To lookup this question, using request like:

curl -X GET "https://asap-api.dataforce.com.au/DATAFORCE_ESS/questions/1243" -H "accept: application/json" -H "Authorization: Bearer xxxxxx"

Return a response like:

{
  "questionId": 1243,
  "question": "Is the site a Residential Building or a Business Building?",
  "type": "Appointment",
  "fieldType": "Radio",
  "checkboxId": 0,
  "dataCategoryId": 0,
  "dataCategory": "",
  "sortOrder": 8,
  "mandatory": true,
  "category": "Standard",
  "customerType": "",
  "createdDate": "2016-09-13T15:45:07+10:00",
  "questionBlockTypeId": 0,
  "questionBlockTypeName": "",
  "parentQuestion": [],
  "workType": [
    4,
    7,
    13
  ],
  "agent": [],
  "calculationZone": [],
  "fieldworkerAbility": []
}

The fieldType has Radio this means that we need to lookup the answer to find right answerId.

We use the answer endpoint, using request like:

curl -X GET "https://asap-api.dataforce.com.au/DATAFORCE_ESS/questions/1243/answers -H "accept: application/json" -H "Authorization: Bearer xxxxxx"

We get a response like :

{
  "totalCount": 2,
  "records": [
    {
      "answerId": 6742,
      "questionId": 1243,
      "answerValue": "residential building",
      "answerText": "Residential Building",
      "sortOrder": 0,
      "mandatory": 0,
      "enabled": false
    },
    {
      "answerId": 6743,
      "questionId": 1243,
      "answerValue": "small business building",
      "answerText": "Business Building",
      "sortOrder": 1,
      "mandatory": 0,
      "enabled": false
    }
  ]
}

The field answerId is what will be needed.

In this strut answerValue is what will be print onto forms or submission data files the answerText is the value displayed on our screen/Runabout a human name. When completing the answer strut for the save endpoint use the value under answerId as the value.

Using the GET endpoint for existing questions.

To view an existing appointment question the use this endpoint GET /{instance}/appointments/{appointment_id}/answers.

Use a request like:

curl -X GET "https://asap-api-dev.dataforce.com.au/DATAFORCE_ESS/appointments/204327/answers" -H "accept: application/json" -H "Authorization: Bearer xxxxxx"

Get the result in common format:

{
  "appointmentId": 204327,
  "blockAnswers": [
    {
      "questionBlockTypeId": 9,
      "blocks": [
        {
          "answers": [
            {
              "questionId": 1151,
              "answerValue": "6643"
            },
            {
              "questionId": 1164,
              "answerValue": "6667"
            },
            {
              "questionId": 1200,
              "answerValue": "8"
            },
            {
              "questionId": 1332,
              "answerValue": "7231"
            },
            {
              "questionId": 1970,
              "answerValue": "8177"
            },
            {
              "questionId": 2050,
              "answerValue": "9089"
            },
            {
              "questionId": 2057,
              "answerValue": "bathroom"
            },
            {
              "questionId": 2169,
              "answerValue": "10028"
            },
            {
              "questionId": 2184,
              "answerValue": "4444"
            }
          ]
        }
      ]
    }
  ],
  "answers": [
    {
      "questionId": 1204,
      "answerValue": "6714"
    },
    {
      "questionId": 1208,
      "answerValue": "6723"
    },
    {
      "questionId": 1241,
      "answerValue": "6741"
    },
    {
      "questionId": 1243,
      "answerValue": "6742"
    },
    {
      "questionId": 1247,
      "answerValue": "30"
    },
    {
      "questionId": 1301,
      "answerValue": "555565"
    },
    {
      "questionId": 1346,
      "answerValue": "7520"
    },
    {
      "questionId": 1347,
      "answerValue": "7522"
    }
  ]
}

You will need to submit this format to next end-point.

Using the POST endpoint to save changes.

Using save endpoint at POST /{instance}/appointments/{appointment_id}/questions will save these answers

Using a POST request like below

curl -X POST "https://asap-api.dataforce.com.au/DATAFORCE_ESS/appointments/204327/questions" -H "accept: application/json" -H "Authorization: Bearer xxxxxx" -H "Content-Type: application/json" -d "{\"appointmentId\":204327,\"blockAnswers\":[{\"questionBlockTypeId\":9,\"blocks\":[{\"answers\":[{\"questionId\":1151,\"answerValue\":\"6643\"},{\"questionId\":1164,\"answerValue\":\"6667\"},{\"questionId\":1200,\"answerValue\":\"8\"},{\"questionId\":1332,\"answerValue\":\"7231\"},{\"questionId\":1970,\"answerValue\":\"8177\"},{\"questionId\":2050,\"answerValue\":\"9089\"},{\"questionId\":2057,\"answerValue\":\"bathroom\"},{\"questionId\":2169,\"answerValue\":\"10028\"},{\"questionId\":2184,\"answerValue\":\"4444\"}]}]}],\"answers\":[{\"questionId\":1204,\"answerValue\":\"6714\"},{\"questionId\":1208,\"answerValue\":\"6723\"},{\"questionId\":1241,\"answerValue\":\"6741\"},{\"questionId\":1243,\"answerValue\":\"6742\"},{\"questionId\":1247,\"answerValue\":\"30\"},{\"questionId\":1301,\"answerValue\":\"555565\"},{\"questionId\":1346,\"answerValue\":\"7520\"},{\"questionId\":1347,\"answerValue\":\"7522\"}]}"

The backend will send back a 201 code with following response.

{
  "appointmentId": 204327
}

Validation Failures

If we tried to submit a an invalid answerId with answerValue we get error like below.

{
  "message": "Unable to complete the process with validation error",
  "errors": [
    {
      "type": "answers/6/answerValue",
      "description": "Answer Value does not match one of the Answers for this question, please use an answerId not answer text"
    }
  ]
}

The type property has message answers/6/answerValue.

From answers property look for 7th record (0 based array) and answerValue field which has incorrect value.

If we tried to submit a non-block question in a block strut will see error like below.

{
  "message": "Unable to complete the process with validation error",
  "errors": [
    {
      "type": "blockAnswers/0/blocks/0/answers/9/questionId",
      "description": "Question does not exists for this Stage or in this Question Block Type"
    }
  ]
}

From the blockAnswers property look for the 1st Block Type and in 1st block and in 10th record in answer array and the error is from the questionId field.

If questionId does not exist or its for a Job/Customer/Audit stage question an error like below will be returned.

{
  "message": "Unable to complete the process with validation error",
  "errors": [
    {
      "type": "answers/7/questionId",
      "description": "Question does not exists at the current stage"
    }
  ]
}

If and invalid datetime format was submitted like below:

{
      "questionId": 2189,
      "answerValue": "25/12/2023"
}

This field type requires (dd/mm/yy) and the above submits (dd/mm/yyyy).

We get error like the following.

{
  "message": "Unable to complete the process with validation error",
  "errors": [
    {
      "type": "answers/8/answerValue",
      "description": "Answer Value must be date with format 'd/m/y'"
    }
  ]
}

The formats using PHP DateTime format.

The question dictionary will have the format in the fieldType property.

{
  "questionId": 2189,
  "question": "Test Date Format",
  "type": "Appointment",
  "fieldType": "Date (DD/MM/YY)",
  "checkboxId": 0,
  "dataCategoryId": 0,
  "dataCategory": "",
  "sortOrder": 3000,
  "mandatory": false,
  ..... 
}