Welcome to the Grid Flow Public API documentation. Our API enables you to programmatically manage grid connection applications, upload and manage documents, and integrate fully with the Grid Flow system without needing the web interface.

Base URL: https://app.renewablehelp.co.uk/api/v1

1. Authentication & API Keys

All API endpoints require authentication via API key. Include your API key in the request header:

X-API-Key: gf_live_your_api_key_here

Obtaining an API Key

  1. Log in to your Grid Flow account at app.renewablehelp.co.uk
  2. Navigate to Account Settings → API Keys
  3. Click Create New API Key
  4. Select the scopes (permissions) you need
  5. Copy and securely store your key (it won’t be shown again)
Security Warning: Never expose your API key in client-side code or public repositories. Always make API calls from your server. API keys start with gf_live_.

2. API Scopes

When creating an API key, you select which scopes (permissions) it has. Only request the scopes you need.

Scope Description
applications:read View applications and their details
applications:write Create new applications and update existing ones
applications:delete Delete draft applications
applications:submit Submit applications for processing (generates documents)
status:write Change application status within allowed transitions
documents:read List and download documents attached to applications
documents:write Upload new documents and delete existing ones
documents:generate Trigger document generation for paper applications
document_requests:read View document request status and details
document_requests:write Create and manage document requests
devices:read Search ENA approved device databases
installers:read View saved installer/contractor information
installers:write Create and update installers
bulk:import Import multiple applications via bulk endpoint

3. Rate Limiting

API requests are rate limited to 1000 requests per hour per API key. Rate limit info is included in response headers:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 945
X-RateLimit-Reset: 2024-01-15T11:00:00Z

4. Applications API

Manage grid connection applications programmatically.

List Applications

GET
/api/v1/applications

applications:read

Query Parameters

Parameter Type Description
status string Optional Filter by status (draft, submitted, approved, etc.)
type string Optional Filter by application_type
dno string Optional Filter by DNO code
mpan string Optional Filter by MPAN (partial match)
reference string Optional Filter by reference number (partial match)
installer_id string Optional Filter by saved installer ID
search string Optional Full text search across name, email, address, reference, MPAN
created_after ISO 8601 Optional Filter by created date
created_before ISO 8601 Optional Filter by created date
limit integer Optional Results per page (default: 50, max: 100)
offset integer Optional Pagination offset

Response

{
“applications”: [
{
“id”: “550e8400-e29b-41d4-a716-446655440000”,
“reference_number”: “FLOW-1704067200-ABC12”,
“application_type”: “solar_pv”,
“submission_method”: “paper”,
“applicant_name”: “John Smith”,
“applicant_email”: “john@example.com”,
“applicant_phone”: “07700900123”,
“applicant_company_name”: “Smith Solar Ltd”,
“site_address”: “123 Solar Street, London, SW1A 1AA”,
“postcode”: “SW1A 1AA”,
“mpan”: “1234567890123”,
“dno_name”: “UK Power Networks”,
“dno_code”: “UKPN”,
“installer_id”: “uuid-of-installer”,
“status”: “submitted”,
“payment_status”: “paid”,
“created_at”: “2024-01-15T10:30:00Z”,
“updated_at”: “2024-01-15T12:00:00Z”
}
],
“pagination”: {
“total”: 156,
“limit”: 50,
“offset”: 0,
“hasMore”: true
}
}

Get Application

GET
/api/v1/applications/{id}

applications:read

Returns full application details including equipment_details and generated_documents JSON fields.

Create Application

POST
/api/v1/applications

applications:write

Request Body

{
“applicationType”: “solar_pv”, // Required: solar_pv, solar_pv_and_battery, battery_storage_only, ev_charger, heat_pump, v2g_ev_charger
“submissionMethod”: “paper”, // Optional: paper (default) or ena_connect
“mpan”: “1234567890123”, // Required for document generation – determines DNO

“applicant”: { // Required
“firstName”: “John”, // Required
“lastName”: “Smith”, // Required
“email”: “john@example.com”, // Required
“phone”: “07700900123”,
“companyName”: “Smith Solar Ltd”,
“address”: “456 Business Park”,
“addressLine2”: “Suite 100”,
“city”: “Manchester”,
“postcode”: “M1 1AA”
},

“site”: { // Required
“street”: “123 Solar Street”, // Required
“addressLine2”: “”,
“city”: “London”, // Required for EV/HP applications
“postcode”: “SW1A 1AA”, // Required
“companyName”: “”, // If site is a business
“contactName”: “Jane Doe”, // Site contact (if different from applicant)
“contactEmail”: “jane@example.com”,
“contactPhone”: “07700900456”
},

“dno”: { // Optional – auto-detected from MPAN
“name”: “UK Power Networks”,
“code”: “UKPN”,
“email”: “connections@ukpn.co.uk”,
“reference”: “”
},

“installerId”: “uuid”, // Optional – reference to saved installer

“equipment”: {
“phase”: 1, // 1 for single phase, 3 for three phase
“fuseSize”: 80, // Main fuse size in amps
“inverters”: [
{
“manufacturer”: “SolarEdge”,
“model”: “SE5000H”,
“capacity”: 5.0, // kW
“enaCode”: “ENS123456”, // ENA registration number
“phase”: 1,
“existing”: false, // Is this an existing installation?
“remove”: false, // Is this being removed?
“panelWattage”: 400,
“panelCount”: 12,
“panelModel”: “JA Solar 400W”,
“battery”: {
“manufacturer”: “Tesla”,
“model”: “Powerwall 2”,
“capacity”: 13.5 // kWh
}
}
],
“evChargers”: [ // For ev_charger/v2g applications
{
“manufacturer”: “Ohme”,
“model”: “Home Pro”,
“capacity”: 7.4,
“enaCode”: “EVC123456”,
“type”: “AC” // AC, DC, or V2G
}
],
“heatPumps”: [ // For heat_pump applications
{
“manufacturer”: “Mitsubishi”,
“model”: “Ecodan PUZ”,
“capacity”: 8.5,
“enaCode”: “HP123456”
}
]
},

“installer”: { // Optional – inline installer details (alternative to installerId)
“companyName”: “Smith Solar Ltd”,
“contactName”: “John Smith”,
“email”: “john@smithsolar.com”,
“phone”: “07700900123”,
“address”: “456 Business Park”,
“city”: “Manchester”,
“postcode”: “M1 1AA”
}
}

Response

{
“message”: “Application created”,
“application”: {
“id”: “550e8400-e29b-41d4-a716-446655440000”,
“referenceNumber”: “FLOW-1704067200-ABC12”,
“applicationType”: “solar_pv”,
“submissionMethod”: “paper”,
“status”: “draft”
}
}

Update Application

PUT
/api/v1/applications/{id}

applications:write

Updates an application. Can update non-draft applications (except protected fields like reference_number and ena_application_id).

{
“mpan”: “1234567890124”,
“applicant”: {
“firstName”: “Jane”,
“lastName”: “Smith”
},
“site”: {
“street”: “124 Updated Street”
},
“equipment”: {
“inverters”: […]
}
}

Delete Application

DELETE
/api/v1/applications/{id}

applications:delete

Deletes a draft application. Only draft status applications can be deleted.

Submit Application

POST
/api/v1/applications/{id}/submit

applications:submit

Submits a draft application for processing. For paper submissions, this generates DNO documents (G98/G99 forms, etc.).

Response (Paper Submission)

{
“message”: “Application submitted and documents generated”,
“status”: “submitted”,
“documentsGenerated”: 3,
“documents”: [
{ “name”: “G98-Application.pdf”, “type”: “G98”, “dno”: “UK Power Networks” },
{ “name”: “LOA.pdf”, “type”: “LOA”, “dno”: “” },
{ “name”: “SLD.pdf”, “type”: “SLD”, “dno”: “” }
]
}

Bulk Create Applications

POST
/api/v1/applications/bulk

bulk:import

Create up to 100 applications in a single request.

{
“applications”: [
{ “applicationType”: “solar_pv”, “applicant”: {…}, “site”: {…}, … },
{ “applicationType”: “heat_pump”, “applicant”: {…}, “site”: {…}, … }
]
}

5. Status Management

Get Application Status

GET
/api/v1/applications/{id}/status

applications:read

Returns current status, available transitions, and status history.

{
“currentStatus”: “submitted”,
“allowedTransitions”: [“documents_sent”, “pending_dno”, “withdrawn”],
“lastUpdated”: “2024-01-15T12:00:00Z”,
“documentsGeneratedAt”: “2024-01-15T10:30:00Z”,
“submissionErrors”: null,
“statusHistory”: [
{ “status”: “submitted”, “details”: {…}, “timestamp”: “2024-01-15T10:30:00Z” },
{ “status”: “draft”, “details”: null, “timestamp”: “2024-01-15T09:00:00Z” }
]
}

Update Application Status

PUT
/api/v1/applications/{id}/status

status:write

Allowed Status Transitions

From Status Allowed Transitions
draft submitted, withdrawn
submitted documents_sent, pending_dno, generation_failed, withdrawn
documents_sent pending_dno, withdrawn
pending_dno more_info_required, withdrawn
generation_failed submitted, withdrawn
more_info_required pending_dno, withdrawn
Note: API users cannot set statuses: approved, rejected, completed, commissioned. These are set by administrators or DNO responses.
{
“status”: “documents_sent”,
“notes”: “Documents emailed to DNO”
}

6. Document Management

List Documents

GET
/api/v1/applications/{id}/documents

documents:read

{
“uploaded”: [
{
“id”: “doc-uuid”,
“name”: “cutout_photo.jpg”,
“type”: “cutout_image”,
“size”: 245760,
“mimeType”: “image/jpeg”,
“uploadedAt”: “2024-01-15T11:00:00Z”
}
],
“generated”: [
{
“id”: “gen-doc-uuid”,
“name”: “G98-Application.pdf”,
“type”: “generated”,
“dno”: “UK Power Networks”,
“path”: “uploads/applications/app-id/g98.pdf”
}
]
}

Download Document

GET
/api/v1/applications/{id}/documents/{documentId}

documents:read

Returns the document file as binary with appropriate Content-Type header.

Upload Document

POST
/api/v1/applications/{id}/documents

documents:write

Upload a document using multipart/form-data:

Field Type Description
file file Required The document file (max 10MB)
type string Optional Document type (cutout_image, mcs_certificate, etc.)

Allowed file types: JPEG, PNG, GIF, PDF, Word documents, Excel spreadsheets

Delete Document

DELETE
/api/v1/applications/{id}/documents/{documentId}

documents:write

Regenerate Documents

POST
/api/v1/applications/{id}/documents/generate

documents:generate

Regenerates DNO documents (G98/G99 forms) for paper submissions. Useful after updating application details.

7. Document Requests

Request specific documents from customers/applicants.

List Document Requests

GET
/api/v1/applications/{id}/document-requests

document_requests:read

Create Document Request

POST
/api/v1/applications/{id}/document-requests

document_requests:write

{
“documentType”: “mcs_certificate”,
“description”: “Please provide your MCS certificate for this installation”,
“deadline”: “2024-01-20T23:59:59Z”
}

Update Document Request

PUT
/api/v1/applications/{id}/document-requests/{requestId}

document_requests:write

{
“status”: “approved”, // pending, uploaded, approved, rejected
“rejectionReason”: “Document expired”
}

Upload for Document Request

POST
/api/v1/applications/{id}/document-requests/{requestId}/upload

documents:write

Upload a document to fulfill a request using multipart/form-data.

8. Device Database

Search ENA approved devices (inverters, heat pumps, EV chargers).

Search Inverters

GET
/api/v1/devices/inverters

devices:read

Parameter Type Description
search string Search in model, manufacturer, ENA registration
manufacturer string Filter by manufacturer
category string Filter by category
limit integer Results (default: 50)

Search Heat Pumps

GET
/api/v1/devices/heatpumps

devices:read

Search EV Chargers

GET
/api/v1/devices/evchargers

devices:read

Additional parameter: v2g=true to filter for V2G-capable chargers.

9. Installers API

Save installer/contractor details for reuse across applications.

List Installers

GET
/api/v1/installers

installers:read

Create Installer

POST
/api/v1/installers

installers:write

{
“companyName”: “Smith Solar Ltd”, // Required
“contactName”: “John Smith”,
“email”: “john@smithsolar.com”,
“phone”: “07700900123”,
“address”: “456 Business Park”,
“city”: “Manchester”,
“postcode”: “M1 1AA”,
“mcsNumber”: “MCS123456”
}

10. Error Handling

Error Response Format

{
“error”: “Validation failed”,
“message”: “MPAN must be 13 digits”,
“validTypes”: [“solar_pv”, “heat_pump”, …] // Additional context when relevant
}

HTTP Status Codes

Code Description
200 Success
201 Created
400 Bad Request – Invalid parameters or validation failed
401 Unauthorized – Invalid or missing API key
403 Forbidden – Insufficient scope/permissions
404 Not Found – Resource doesn’t exist or not owned by you
429 Too Many Requests – Rate limit exceeded
500 Internal Server Error
503 Service Unavailable – Document generation service not configured

11. Code Examples

cURL

# List applications
curl -X GET “https://app.renewablehelp.co.uk/api/v1/applications?status=draft&limit=10” \
-H “X-API-Key: gf_live_your_api_key”

# Create application
curl -X POST “https://app.renewablehelp.co.uk/api/v1/applications” \
-H “X-API-Key: gf_live_your_api_key” \
-H “Content-Type: application/json” \
-d ‘{
“applicationType”: “solar_pv”,
“mpan”: “1234567890123”,
“applicant”: {
“firstName”: “John”,
“lastName”: “Smith”,
“email”: “john@example.com”
},
“site”: {
“street”: “123 Solar Street”,
“city”: “London”,
“postcode”: “SW1A 1AA”
},
“equipment”: {
“inverters”: [{
“manufacturer”: “SolarEdge”,
“model”: “SE5000H”,
“capacity”: 5.0
}]
}
}’

# Submit application
curl -X POST “https://app.renewablehelp.co.uk/api/v1/applications/{id}/submit” \
-H “X-API-Key: gf_live_your_api_key”

# Upload document
curl -X POST “https://app.renewablehelp.co.uk/api/v1/applications/{id}/documents” \
-H “X-API-Key: gf_live_your_api_key” \
-F “file=@/path/to/cutout.jpg” \
-F “type=cutout_image”

# Download document
curl -X GET “https://app.renewablehelp.co.uk/api/v1/applications/{id}/documents/{docId}” \
-H “X-API-Key: gf_live_your_api_key” \
–output document.pdf

JavaScript (Node.js)

const axios = require(‘axios’);
const FormData = require(‘form-data’);
const fs = require(‘fs’);

const API_KEY = ‘gf_live_your_api_key’;
const BASE_URL = ‘https://app.renewablehelp.co.uk/api/v1’;

const api = axios.create({
baseURL: BASE_URL,
headers: { ‘X-API-Key’: API_KEY }
});

// List applications
async function listApplications(filters = {}) {
const response = await api.get(‘/applications’, { params: filters });
return response.data;
}

// Create application
async function createApplication(data) {
const response = await api.post(‘/applications’, data);
return response.data;
}

// Submit application
async function submitApplication(id) {
const response = await api.post(`/applications/${id}/submit`);
return response.data;
}

// Upload document
async function uploadDocument(appId, filePath, type) {
const form = new FormData();
form.append(‘file’, fs.createReadStream(filePath));
form.append(‘type’, type);

const response = await api.post(`/applications/${appId}/documents`, form, {
headers: form.getHeaders()
});
return response.data;
}

// Example usage
async function main() {
// Create and submit an application
const app = await createApplication({
applicationType: ‘solar_pv’,
mpan: ‘1234567890123’,
applicant: { firstName: ‘John’, lastName: ‘Smith’, email: ‘john@example.com’ },
site: { street: ‘123 Solar Street’, city: ‘London’, postcode: ‘SW1A 1AA’ },
equipment: { inverters: [{ manufacturer: ‘SolarEdge’, model: ‘SE5000H’, capacity: 5.0 }] }
});

console.log(‘Created:’, app.application.referenceNumber);

// Submit to generate documents
const result = await submitApplication(app.application.id);
console.log(‘Documents generated:’, result.documentsGenerated);
}

main().catch(console.error);

Python

import requests

API_KEY = ‘gf_live_your_api_key’
BASE_URL = ‘https://app.renewablehelp.co.uk/api/v1’

headers = {
‘X-API-Key’: API_KEY,
‘Content-Type’: ‘application/json’
}

def list_applications(**filters):
response = requests.get(f'{BASE_URL}/applications’, headers=headers, params=filters)
response.raise_for_status()
return response.json()

def create_application(data):
response = requests.post(f'{BASE_URL}/applications’, headers=headers, json=data)
response.raise_for_status()
return response.json()

def submit_application(app_id):
response = requests.post(f'{BASE_URL}/applications/{app_id}/submit’, headers=headers)
response.raise_for_status()
return response.json()

def upload_document(app_id, file_path, doc_type):
with open(file_path, ‘rb’) as f:
files = {‘file’: f}
data = {‘type’: doc_type}
response = requests.post(
f'{BASE_URL}/applications/{app_id}/documents’,
headers={‘X-API-Key’: API_KEY},
files=files,
data=data
)
response.raise_for_status()
return response.json()

# Example usage
if __name__ == ‘__main__’:
app = create_application({
‘applicationType’: ‘solar_pv’,
‘mpan’: ‘1234567890123’,
‘applicant’: {‘firstName’: ‘John’, ‘lastName’: ‘Smith’, ’email’: ‘john@example.com’},
‘site’: {‘street’: ‘123 Solar Street’, ‘city’: ‘London’, ‘postcode’: ‘SW1A 1AA’},
‘equipment’: {‘inverters’: [{‘manufacturer’: ‘SolarEdge’, ‘model’: ‘SE5000H’, ‘capacity’: 5.0}]}
})
print(f”Created: {app[‘application’][‘referenceNumber’]}”)

result = submit_application(app[‘application’][‘id’])
print(f”Documents generated: {result[‘documentsGenerated’]}”)

PHP

<?php

$apiKey = ‘gf_live_your_api_key’;
$baseUrl = ‘https://app.renewablehelp.co.uk/api/v1’;

function apiRequest($endpoint, $method = ‘GET’, $data = null) {
global $apiKey, $baseUrl;

$ch = curl_init();
$url = $baseUrl . $endpoint;

$headers = [“X-API-Key: $apiKey”];

if ($method === ‘POST’ || $method === ‘PUT’) {
$headers[] = ‘Content-Type: application/json’;
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}

if ($method === ‘POST’) curl_setopt($ch, CURLOPT_POST, true);
if ($method === ‘PUT’) curl_setopt($ch, CURLOPT_CUSTOMREQUEST, ‘PUT’);
if ($method === ‘DELETE’) curl_setopt($ch, CURLOPT_CUSTOMREQUEST, ‘DELETE’);

curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $headers
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

return [‘code’ => $httpCode, ‘data’ => json_decode($response, true)];
}

// List applications
$result = apiRequest(‘/applications?status=draft&limit=10’);
print_r($result[‘data’]);

// Create application
$app = apiRequest(‘/applications’, ‘POST’, [
‘applicationType’ => ‘solar_pv’,
‘mpan’ => ‘1234567890123’,
‘applicant’ => [‘firstName’ => ‘John’, ‘lastName’ => ‘Smith’, ’email’ => ‘john@example.com’],
‘site’ => [‘street’ => ‘123 Solar Street’, ‘city’ => ‘London’, ‘postcode’ => ‘SW1A 1AA’],
‘equipment’ => [‘inverters’ => [[‘manufacturer’ => ‘SolarEdge’, ‘model’ => ‘SE5000H’, ‘capacity’ => 5.0]]]
]);

echo “Created: ” . $app[‘data’][‘application’][‘referenceNumber’] . “\n”;

// Submit
$appId = $app[‘data’][‘application’][‘id’];
$result = apiRequest(“/applications/$appId/submit”, ‘POST’);
echo “Documents generated: ” . $result[‘data’][‘documentsGenerated’] . “\n”;

Need Help?

If you have questions or need assistance with the API: