Installer.com Docs

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 IDTypeDescription
mpantextMeter Point Administration Number
declared-voltage-at-connection-pointtextDeclared voltage at the connection point
number-of-phasesnumberPhase code (e.g. 1 or 3)
is-ct-meteredbooleanWhether the supply is CT metered
premises-cut-out-ratingnumberCut-out rating in amps
is-the-service-loopedbooleanWhether the service is looped
is-no-safety-concernsbooleanConfirmation of no safety concerns
max-import-capacitytextMaximum import capacity (optional)
is-no-issuesbooleanConfirmation of no issues
is-import-limiting-device-presentbooleanWhether an import-limiting device is fitted
device-sys-reftextInstaller reference for the device
proposed-date-installdateProposed install date
new-premises-max-demandtextNew premises maximum demand
cut-out-image-uploadfilePhoto 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:

FieldEffect
Complete status valuesWhen the response status matches one of these, the workflow step auto-transitions to done and downstream steps activate.
Reject status valuesWhen 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

IssueSolution
Invalid JSON errorA 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 emptyThe 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 emptyThe 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 applicationCheck 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 fireVerify 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.

On this page