Create Interim Report
curl --request POST \
--url https://api.n-3.co.uk/reports/drawdown \
--header 'Content-Type: application/json' \
--data '
{
"project_id": {},
"month": 123,
"year": 123,
"edition": 123,
"comments": "<string>",
"aggregate": {
"amount": 123,
"surplus_shortfall": 123
},
"facility": [
{
"facility_id": {},
"amount": 123,
"surplus_shortfall": 123
}
],
"riskStatus": [
{
"input_setting_id": {},
"risk_status_legend_id": {},
"notes": "<string>"
}
],
"visit": {
"date": "<string>",
"notes": "<string>",
"files": [
{
"filename": "<string>",
"s3_location": "<string>",
"file_size": 123,
"mime_type": "<string>"
}
]
}
}
'import requests
url = "https://api.n-3.co.uk/reports/drawdown"
payload = {
"project_id": {},
"month": 123,
"year": 123,
"edition": 123,
"comments": "<string>",
"aggregate": {
"amount": 123,
"surplus_shortfall": 123
},
"facility": [
{
"facility_id": {},
"amount": 123,
"surplus_shortfall": 123
}
],
"riskStatus": [
{
"input_setting_id": {},
"risk_status_legend_id": {},
"notes": "<string>"
}
],
"visit": {
"date": "<string>",
"notes": "<string>",
"files": [
{
"filename": "<string>",
"s3_location": "<string>",
"file_size": 123,
"mime_type": "<string>"
}
]
}
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
project_id: {},
month: 123,
year: 123,
edition: 123,
comments: '<string>',
aggregate: {amount: 123, surplus_shortfall: 123},
facility: [{facility_id: {}, amount: 123, surplus_shortfall: 123}],
riskStatus: [{input_setting_id: {}, risk_status_legend_id: {}, notes: '<string>'}],
visit: {
date: '<string>',
notes: '<string>',
files: [
{
filename: '<string>',
s3_location: '<string>',
file_size: 123,
mime_type: '<string>'
}
]
}
})
};
fetch('https://api.n-3.co.uk/reports/drawdown', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.n-3.co.uk/reports/drawdown",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'project_id' => [
],
'month' => 123,
'year' => 123,
'edition' => 123,
'comments' => '<string>',
'aggregate' => [
'amount' => 123,
'surplus_shortfall' => 123
],
'facility' => [
[
'facility_id' => [
],
'amount' => 123,
'surplus_shortfall' => 123
]
],
'riskStatus' => [
[
'input_setting_id' => [
],
'risk_status_legend_id' => [
],
'notes' => '<string>'
]
],
'visit' => [
'date' => '<string>',
'notes' => '<string>',
'files' => [
[
'filename' => '<string>',
's3_location' => '<string>',
'file_size' => 123,
'mime_type' => '<string>'
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.n-3.co.uk/reports/drawdown"
payload := strings.NewReader("{\n \"project_id\": {},\n \"month\": 123,\n \"year\": 123,\n \"edition\": 123,\n \"comments\": \"<string>\",\n \"aggregate\": {\n \"amount\": 123,\n \"surplus_shortfall\": 123\n },\n \"facility\": [\n {\n \"facility_id\": {},\n \"amount\": 123,\n \"surplus_shortfall\": 123\n }\n ],\n \"riskStatus\": [\n {\n \"input_setting_id\": {},\n \"risk_status_legend_id\": {},\n \"notes\": \"<string>\"\n }\n ],\n \"visit\": {\n \"date\": \"<string>\",\n \"notes\": \"<string>\",\n \"files\": [\n {\n \"filename\": \"<string>\",\n \"s3_location\": \"<string>\",\n \"file_size\": 123,\n \"mime_type\": \"<string>\"\n }\n ]\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.n-3.co.uk/reports/drawdown")
.header("Content-Type", "application/json")
.body("{\n \"project_id\": {},\n \"month\": 123,\n \"year\": 123,\n \"edition\": 123,\n \"comments\": \"<string>\",\n \"aggregate\": {\n \"amount\": 123,\n \"surplus_shortfall\": 123\n },\n \"facility\": [\n {\n \"facility_id\": {},\n \"amount\": 123,\n \"surplus_shortfall\": 123\n }\n ],\n \"riskStatus\": [\n {\n \"input_setting_id\": {},\n \"risk_status_legend_id\": {},\n \"notes\": \"<string>\"\n }\n ],\n \"visit\": {\n \"date\": \"<string>\",\n \"notes\": \"<string>\",\n \"files\": [\n {\n \"filename\": \"<string>\",\n \"s3_location\": \"<string>\",\n \"file_size\": 123,\n \"mime_type\": \"<string>\"\n }\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.n-3.co.uk/reports/drawdown")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"project_id\": {},\n \"month\": 123,\n \"year\": 123,\n \"edition\": 123,\n \"comments\": \"<string>\",\n \"aggregate\": {\n \"amount\": 123,\n \"surplus_shortfall\": 123\n },\n \"facility\": [\n {\n \"facility_id\": {},\n \"amount\": 123,\n \"surplus_shortfall\": 123\n }\n ],\n \"riskStatus\": [\n {\n \"input_setting_id\": {},\n \"risk_status_legend_id\": {},\n \"notes\": \"<string>\"\n }\n ],\n \"visit\": {\n \"date\": \"<string>\",\n \"notes\": \"<string>\",\n \"files\": [\n {\n \"filename\": \"<string>\",\n \"s3_location\": \"<string>\",\n \"file_size\": 123,\n \"mime_type\": \"<string>\"\n }\n ]\n }\n}"
response = http.request(request)
puts response.read_body{
"400": {},
"403": {},
"404": {},
"id": {},
"created_date": "<string>",
"project_id": {},
"month": 123,
"year": 123,
"edition": 123,
"template_id": {},
"type": "<string>"
}Reports
Create Interim Report
Create a new interim report with comprehensive drawdown tracking, risk assessments, and site visit documentation
POST
/
reports
/
drawdown
Create Interim Report
curl --request POST \
--url https://api.n-3.co.uk/reports/drawdown \
--header 'Content-Type: application/json' \
--data '
{
"project_id": {},
"month": 123,
"year": 123,
"edition": 123,
"comments": "<string>",
"aggregate": {
"amount": 123,
"surplus_shortfall": 123
},
"facility": [
{
"facility_id": {},
"amount": 123,
"surplus_shortfall": 123
}
],
"riskStatus": [
{
"input_setting_id": {},
"risk_status_legend_id": {},
"notes": "<string>"
}
],
"visit": {
"date": "<string>",
"notes": "<string>",
"files": [
{
"filename": "<string>",
"s3_location": "<string>",
"file_size": 123,
"mime_type": "<string>"
}
]
}
}
'import requests
url = "https://api.n-3.co.uk/reports/drawdown"
payload = {
"project_id": {},
"month": 123,
"year": 123,
"edition": 123,
"comments": "<string>",
"aggregate": {
"amount": 123,
"surplus_shortfall": 123
},
"facility": [
{
"facility_id": {},
"amount": 123,
"surplus_shortfall": 123
}
],
"riskStatus": [
{
"input_setting_id": {},
"risk_status_legend_id": {},
"notes": "<string>"
}
],
"visit": {
"date": "<string>",
"notes": "<string>",
"files": [
{
"filename": "<string>",
"s3_location": "<string>",
"file_size": 123,
"mime_type": "<string>"
}
]
}
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
project_id: {},
month: 123,
year: 123,
edition: 123,
comments: '<string>',
aggregate: {amount: 123, surplus_shortfall: 123},
facility: [{facility_id: {}, amount: 123, surplus_shortfall: 123}],
riskStatus: [{input_setting_id: {}, risk_status_legend_id: {}, notes: '<string>'}],
visit: {
date: '<string>',
notes: '<string>',
files: [
{
filename: '<string>',
s3_location: '<string>',
file_size: 123,
mime_type: '<string>'
}
]
}
})
};
fetch('https://api.n-3.co.uk/reports/drawdown', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.n-3.co.uk/reports/drawdown",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'project_id' => [
],
'month' => 123,
'year' => 123,
'edition' => 123,
'comments' => '<string>',
'aggregate' => [
'amount' => 123,
'surplus_shortfall' => 123
],
'facility' => [
[
'facility_id' => [
],
'amount' => 123,
'surplus_shortfall' => 123
]
],
'riskStatus' => [
[
'input_setting_id' => [
],
'risk_status_legend_id' => [
],
'notes' => '<string>'
]
],
'visit' => [
'date' => '<string>',
'notes' => '<string>',
'files' => [
[
'filename' => '<string>',
's3_location' => '<string>',
'file_size' => 123,
'mime_type' => '<string>'
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.n-3.co.uk/reports/drawdown"
payload := strings.NewReader("{\n \"project_id\": {},\n \"month\": 123,\n \"year\": 123,\n \"edition\": 123,\n \"comments\": \"<string>\",\n \"aggregate\": {\n \"amount\": 123,\n \"surplus_shortfall\": 123\n },\n \"facility\": [\n {\n \"facility_id\": {},\n \"amount\": 123,\n \"surplus_shortfall\": 123\n }\n ],\n \"riskStatus\": [\n {\n \"input_setting_id\": {},\n \"risk_status_legend_id\": {},\n \"notes\": \"<string>\"\n }\n ],\n \"visit\": {\n \"date\": \"<string>\",\n \"notes\": \"<string>\",\n \"files\": [\n {\n \"filename\": \"<string>\",\n \"s3_location\": \"<string>\",\n \"file_size\": 123,\n \"mime_type\": \"<string>\"\n }\n ]\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.n-3.co.uk/reports/drawdown")
.header("Content-Type", "application/json")
.body("{\n \"project_id\": {},\n \"month\": 123,\n \"year\": 123,\n \"edition\": 123,\n \"comments\": \"<string>\",\n \"aggregate\": {\n \"amount\": 123,\n \"surplus_shortfall\": 123\n },\n \"facility\": [\n {\n \"facility_id\": {},\n \"amount\": 123,\n \"surplus_shortfall\": 123\n }\n ],\n \"riskStatus\": [\n {\n \"input_setting_id\": {},\n \"risk_status_legend_id\": {},\n \"notes\": \"<string>\"\n }\n ],\n \"visit\": {\n \"date\": \"<string>\",\n \"notes\": \"<string>\",\n \"files\": [\n {\n \"filename\": \"<string>\",\n \"s3_location\": \"<string>\",\n \"file_size\": 123,\n \"mime_type\": \"<string>\"\n }\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.n-3.co.uk/reports/drawdown")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"project_id\": {},\n \"month\": 123,\n \"year\": 123,\n \"edition\": 123,\n \"comments\": \"<string>\",\n \"aggregate\": {\n \"amount\": 123,\n \"surplus_shortfall\": 123\n },\n \"facility\": [\n {\n \"facility_id\": {},\n \"amount\": 123,\n \"surplus_shortfall\": 123\n }\n ],\n \"riskStatus\": [\n {\n \"input_setting_id\": {},\n \"risk_status_legend_id\": {},\n \"notes\": \"<string>\"\n }\n ],\n \"visit\": {\n \"date\": \"<string>\",\n \"notes\": \"<string>\",\n \"files\": [\n {\n \"filename\": \"<string>\",\n \"s3_location\": \"<string>\",\n \"file_size\": 123,\n \"mime_type\": \"<string>\"\n }\n ]\n }\n}"
response = http.request(request)
puts response.read_body{
"400": {},
"403": {},
"404": {},
"id": {},
"created_date": "<string>",
"project_id": {},
"month": 123,
"year": 123,
"edition": 123,
"template_id": {},
"type": "<string>"
}Create a detailed interim report for tracking project progress during active project phases. This endpoint combines financial drawdown data, risk status assessments, and site visit documentation into a single comprehensive report.
Request Body
bigint
required
The unique identifier of the project for which the interim report is being created
number
required
The month of the reporting period (1-12)
number
required
The year of the reporting period
number
The edition number of the report (defaults to 1 for new reports)
string
General comments or notes about the project status for this reporting period
object
required
array
required
array
required
object
Site visit information (optional, only include if a site visit occurred)
Show visit
Show visit
string
Date of the site visit in YYYY-MM-DD format
string
Detailed notes from the site visit
Example Request
{
"project_id": "123456789",
"month": 6,
"year": 2024,
"edition": 1,
"comments": "Q2 progress showing strong advancement on main structure",
"aggregate": {
"amount": 150000,
"surplus_shortfall": 5000
},
"facility": [
{
"facility_id": "987654321",
"amount": 75000,
"surplus_shortfall": 2500
},
{
"facility_id": "987654322",
"amount": 75000,
"surplus_shortfall": 2500
}
],
"riskStatus": [
{
"input_setting_id": "111",
"risk_status_legend_id": "222",
"notes": "Risk level maintained at low due to good weather conditions"
},
{
"input_setting_id": "333",
"risk_status_legend_id": "444",
"notes": "Material delivery risk increased due to supply chain delays"
}
],
"visit": {
"date": "2024-06-15",
"notes": "Foundation work completed ahead of schedule. Steel frame installation proceeding well. No safety issues observed.",
"files": [
{
"filename": "foundation_complete.jpg",
"s3_location": "projects/123456789/site-visits/2024-06/foundation_complete.jpg",
"file_size": 2048576,
"mime_type": "image/jpeg"
},
{
"filename": "steel_frame_progress.jpg",
"s3_location": "projects/123456789/site-visits/2024-06/steel_frame_progress.jpg",
"file_size": 1536789,
"mime_type": "image/jpeg"
}
]
}
}
Response
Returns the created report with its unique identifier:bigint
Unique identifier of the created interim report
string
ISO timestamp when the report was created
bigint
ID of the associated project
number
Month of the reporting period
number
Year of the reporting period
number
Edition number of the report
bigint
ID of the template used for report generation
string
Report type (will be “INTERIM_REPORT”)
Example Response
{
"id": "789012345",
"created_date": "2024-06-20T10:30:00.000Z",
"project_id": "123456789",
"month": 6,
"year": 2024,
"edition": 1,
"template_id": "555666777",
"type": "INTERIM_REPORT"
}
Automatic Actions
When an interim report is successfully created, the system automatically:- Creates Project Event: Logs a
REPORT_UPLOADEDevent for audit tracking - Updates Project Comments: Saves the comments field to the project record
- Applies Template: Uses the first available interim report template for the environment
- Validates Data: Ensures all required data relationships exist and are valid
Error Responses
error
Bad Request - Missing required fields or invalid data format
{
"statusCode": 400,
"message": "Project ID is required",
"error": "Bad Request"
}
error
Forbidden - User does not have access to the specified project
{
"statusCode": 403,
"message": "User does not have access to this project",
"error": "Forbidden"
}
error
Not Found - Project or referenced entities not found
{
"statusCode": 404,
"message": "Project not found",
"error": "Not Found"
}
Notes
- All monetary amounts should be provided as numbers (not strings)
- Site visit information is optional - omit the entire
visitobject if no visit occurred - Risk status assessments are required for all interim reports
- The system automatically determines the appropriate template based on the project’s environment
- File uploads must be completed separately before creating the report - provide S3 locations in the request

