DNO Integration
Submit UK grid connection applications to ENA Connect from a workflow step
Overview
The DNO (Distribution Network Operator) integration submits grid connection applications to ENA Connect as part of an order's workflow. It is used for installations that require notification or approval from a UK network operator, typically EV chargers, solar PV, battery storage, and heat pumps.
The integration is implemented as a background event on a workflow step. When the step reaches the configured state, Installer.com renders a Handlebars payload from the order's custom fields and posts it to ENA Connect.
The DNO integration currently supports the United Kingdom only via ENA Connect. Other regions are not supported.
How It Works
Order created
The order is created from a template that includes the DNO custom fields and a workflow step with a DNO background event attached.
Step reaches the trigger state
When the configured workflow step transitions into its trigger state (e.g. active or done), the background event fires.
Payload rendered and submitted
The Handlebars payload is resolved using the order, actors, and custom field values. Any {{dnoFile ...}} references are expanded to file URLs. The rendered JSON is posted to ENA Connect using Installer.com's API token.
Application ID stored on the workflow
ENA Connect returns an applicationId for the submission. Installer.com stores the full response on workflow.eventData.<eventKey> so that later steps can reference it (e.g. workflow.eventData.dno_application_submit.applicationId).
Status polled until approval
A follow-up background event polls ENA Connect on a schedule using the stored applicationId. When the application reaches a terminal status (approved or rejected), the workflow step auto-completes (or rejects), and downstream steps such as Book Installation become active.
Authentication
You do not need your own ENA Connect account. Installer.com provides you with an ENA Connect API token, which you configure on the background event's headers template (typically as X-API-Key). All requests, including file uploads, share the same token.
Contact your account manager to receive a token for your organisation.
Configuring the background event
Open the workflow template
In the Routing App, open the workflow template the order will use. Select the step that should trigger the DNO submission. This is typically a custom step named "DNO Application" placed before booking installation.
Add a DNO background event
On the step, open the Background events tab and add a DNO event. Choose the workflow state that should trigger it (commonly active when the step becomes the current step, or done when it is completed).
Edit the payload
Paste your Handlebars payload (see Example payload) and map the {{customFields.*}} placeholders to the custom IDs on your order template.
Handlebars in the payload
The payload is a JSON string rendered with Handlebars at submission time. The same template features documented in Webhooks → Handlebars syntax apply here: variable interpolation, dot notation, and {{#if}} / {{#each}} blocks.
In addition to the standard variables, the DNO integration provides a dnoFile helper for attaching files from the order to the application.
dnoFile helper
{{dnoFile <customId>}} reads a file-type custom field from the order, uploads each file to ENA Connect as part of submission, and returns the URLs ENA Connect issues for those uploaded files. Use it inside an {{#each}} block to emit one entry per uploaded file, or with {{#if @first}} to pick only the first file:
"cutOutImages": [
{{#each {{dnoFile cut-out-image-upload}}}}
{{#if @first}} { "fileUrl": "{{this}}" } {{/if}}
{{/each}}
]Pass the custom field's custom ID (e.g. cut-out-image-upload), not its UUID. Custom IDs are configured on the custom field in the order template.
Required custom fields
The DNO payload pulls values from the order's custom fields. The exact set depends on the application class, but a typical EVCP-AC submission expects the following custom IDs on the order template:
| Custom ID | Type | Description |
|---|---|---|
mpan | text | Meter Point Administration Number |
declared-voltage-at-connection-point | text | Declared voltage at the connection point |
number-of-phases | number | Phase code (e.g. 1 or 3) |
is-ct-metered | boolean | Whether the supply is CT metered |
premises-cut-out-rating | number | Cut-out rating in amps |
is-the-service-looped | boolean | Whether the service is looped |
is-no-safety-concerns | boolean | Confirmation of no safety concerns |
max-import-capacity | text | Maximum import capacity (optional) |
is-no-issues | boolean | Confirmation of no issues |
is-import-limiting-device-present | boolean | Whether an import-limiting device is fitted |
device-sys-ref | text | Installer reference for the device |
proposed-date-install | date | Proposed install date |
new-premises-max-demand | text | New premises maximum demand |
cut-out-image-upload | file | Photo of the cut-out (resolved via dnoFile) |
The customer and installer details ({{order.*}}, {{actor.installer.*}}) are sourced from the order and the installer actor on the workflow, so no extra custom fields are required for those.
Booleans must be emitted as raw true / false in the JSON, not strings. Use {{#if customFields.flag}}true{{else}}false{{/if}} for boolean fields.
Example payload
The payload below is a complete EVCP_AC application for ENA Connect. Adjust the applicationClass, lcts, deviceClass, and deviceType for other device types.
{
"applicationClass": "DEMAND_GENERAL",
"applicationClassVersion": 1,
"lcts": [
"EVCP_AC"
],
"subInstallerUsername": "{{actor.installer.organizationName}}",
"installerCustomerDetails": {
"installerName": "{{actor.installer.organizationResponsibleFirstName}} {{actor.installer.organizationResponsibleLastName}}",
"installerCompany": "{{actor.installer.organizationName}}",
"installerPhone": "{{actor.installer.organizationResponsiblePhoneNumber}}",
"customerPhone": "{{order.phoneNumber}}",
"installerEmail": "{{actor.installer.organizationResponsibleEmail}}",
"customerName": "{{order.contactPersonName}}",
"customerEmail": "{{order.email}}",
"mainAddress": "{{order.address}}",
"installationPostCode": "{{order.postalCode}}",
"mpan": "{{customFields.mpan}}"
},
"supplyDetails": {
"declaredVoltageAtConnectionPoint": "{{customFields.declared-voltage-at-connection-point}}",
"phaseCode": {{customFields.number-of-phases}},
"isCtMetered": {{#if customFields.is-ct-metered}}true{{else}}false{{/if}},
"premisesCutOutRating": {{customFields.premises-cut-out-rating}},
"isLoopedSupply": {{#if customFields.is-the-service-looped}}true{{else}}false{{/if}},
"isNoSafetyConcerns": {{#if customFields.is-no-safety-concerns}}true{{else}}false{{/if}},
{{#if customFields.max-import-capacity}}"maxImportCapacity": "{{customFields.max-import-capacity}}",{{/if}}
"isNoIssues": {{#if customFields.is-no-issues}}true{{else}}false{{/if}},
"isImportLimitingDevicePresent": {{#if customFields.is-import-limiting-device-present}}true{{else}}false{{/if}}
},
"devicesToInstall": [
{
"deviceClass": "DEMAND_DEVICE_GENERAL_ENA_REGISTERED",
"deviceType": "EVCP_AC",
"deviceSysRef": "{{customFields.device-sys-ref}}",
"targetInstallDate": "{{customFields.proposed-date-install}}",
"enaLctDataset": "EVAC",
"powerFactor": 1
}
],
"existingDevices": [],
"newPremisesMaxDemand": {
"newPremisesMaxDemand": "{{customFields.new-premises-max-demand}}"
},
"cutOutImages": [
{{#each {{dnoFile cut-out-image-upload}}}}
{{#if @first}} { "fileUrl": "{{this}}"} {{/if}}
{{/each}}
],
"additionalAttachments": []
}The {{actor.installer.*}} variables resolve from the actor with slug installer on the workflow. The slug must match the actor configured on your workflow, typically populated by a preceding Dispatching step. Rename it if your template uses a different slug.
Polling and auto-completion
After a submit background event succeeds, the response from ENA Connect (including the applicationId) is stored on the workflow as workflow.eventData.<eventKey>, where <eventKey> is the data key you configure on the event. With the conventional key dno_application_submit, the application ID becomes available at:
{{workflow.eventData.dno_application_submit.applicationId}}A second background event polls ENA Connect on a schedule against the stored application ID:
GET https://hybrid.connect-direct.energynetworks.org/connection-application/v2/applications?applicationId={{workflow.eventData.dno_application_submit.applicationId}}Each poll inspects the response and compares it against two configurable lists on the event:
| Field | Effect |
|---|---|
| Complete status values | When the response status matches one of these, the workflow step auto-transitions to done and downstream steps activate. |
| Reject status values | When the response status matches one of these, the workflow step auto-transitions to rejected and is surfaced on the order timeline. |
If the status doesn't match either list, the poll reschedules itself and runs again on the configured interval. Because the step auto-completes on approval, no manual action is required on the order once the application has been submitted: booking and installation can proceed as soon as ENA Connect approves the application.
If your workflow uses a different data key for the submit event, replace dno_application_submit in the URL with that key. The key is shown next to the background event in the workflow editor.
Auto-rejection only applies to workflow steps that depend on a previous step. If the DNO step has no dependency configured, a rejected status will not transition the step automatically. Auto-completion works regardless of dependencies.
Expiration
Polling does not run forever. Each background event has an expires after value (default: 7 days from when the step became active). If ENA Connect has not returned a terminal status before that window elapses, the workflow step transitions to expired and polling stops. Configure the expiry on the background event to match your DNO's expected processing time.
Monitoring submissions
Each background event execution is logged on the workflow step with the rendered payload, the HTTP response, and any error returned by ENA Connect. Open the step in the Routing App and inspect the background event history to see the submission status.
For programmatic monitoring, subscribe to workflow webhooks (see Webhooks) on the same step to be notified when the step completes after a successful submission.
Troubleshooting
| Issue | Solution |
|---|---|
| Invalid JSON error | A Handlebars expression is not wrapped in quotes, or a boolean / number is emitted as a string. Use {{#if}}true{{else}}false{{/if}} for booleans and bare {{customFields.value}} (no quotes) for numbers. |
{{actor.installer.*}} is empty | The installer has not been dispatched yet. The DNO step must come after a completed Dispatching step for the installer actor (or rename the slug to match your workflow). |
cutOutImages is empty | The custom ID passed to dnoFile does not match a file field on the order, or no file has been uploaded. Custom IDs are case-sensitive. |
| ENA Connect rejects the application | Check the response logged on the background event execution. Common causes: invalid MPAN, missing required device fields, or the postal code is outside ENA Connect's coverage. |
| Background event did not fire | Verify the step actually transitioned into the configured trigger state and that the background event is attached to the correct state. |
If issues persist, contact support with the order ID and the background event execution timestamp.