Some data only exists once an officer has looked at the application: a decision number, an inspection result, a UPI, a contract start date. The officer form (also called the third-party form) collects it. About one real service in three has one; the demo has none, so you add one below. Structure and examples: Officers third-party form and its general structure.

6. Officer Form
How officer forms work
| Rule | What it means |
|---|---|
| The form belongs to a transition | Its key is [START STATE]-[EVENT], for example PENDING_OFFICER_PROCESSING-APPROVE_WITH_FORM. The engine looks the form up with the application's current state and the event the officer fires |
| Use the event APPROVE_WITH_FORM | Plain APPROVE runs immediately and never opens a form. The officer portal opens the form for APPROVE_WITH_FORM |
| Same building blocks as the applicant form | Sections, blocks, fields, the required pattern and validation messages from A6 and A6b |
| No inputs, no transition | APPROVE_WITH_FORM without any officer input fails with MISSING_OFFICER_INPUTS; the application stays where it was |
| Inputs become application data | The engine validates the inputs against the form and stores them as application details, under their field keys. Certificates and notifications read them like any form answer |
| Who and when | Every officer action also adds [event]_user and [event]_date: approve_with_form_user is the officer's name, approve_with_form_date the date (dd/MM/yyyy) |
A one-field officer form (trimmed)
{
"PENDING_OFFICER_PROCESSING-APPROVE_WITH_FORM": {
"fields": [{
"type": "sections",
"fieldGroup": [{
"key": "SECTION_DECISION", "type": "formly-group", "props": { "label": "Decision" },
"fieldGroup": [{
"key": "BLOCK_DECISION", "type": "block", "props": { "label": "Decision" },
"fieldGroup": [{
"key": "decisionNumber",
"type": "input",
"props": { "label": "Decision number", "pattern": "^DEC-[0-9]{4}$",
"required": false, "defaultRequired": true },
"validation": { "messages": { "pattern": "Use the format DEC-1234." } },
"expressions": { "props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired" }
}]
}]
}]
}]
}
}
${decisionNumber!""}exercise: add a decision number to the approval
- In a practice change request, change the officer's approval transition (PENDING_OFFICER_PROCESSING → APPROVED) from
APPROVEtoAPPROVE_WITH_FORM. Keep its actions.- In 6. Officer Form, add the form above under the key
PENDING_OFFICER_PROCESSING-APPROVE_WITH_FORM.- In the approval notification, add "Decision ${decisionNumber!""}, approved by ${approve_with_form_user!""} on ${approve_with_form_date!""}."
- Test: apply, pay, open the application as the officer, click the approval button. The form opens; try
123(refused), thenDEC-0042. Check the SMS or email.
Gotcha · the key must match the state exactly
If the workflow calls the state
PENDING_OFFICER_PROCESSING_LEVEL_1, the key isPENDING_OFFICER_PROCESSING_LEVEL_1-APPROVE_WITH_FORM. A typo means the engine finds no form for that state and event, and the approval fails. Copy the state code from the workflow.
An officer clicks the APPROVE_WITH_FORM button but the request carries no officer inputs. What happens?
A. APPROVE_WITH_FORM needs inputs. That is also why you never use it on a transition that has no officer form.