Save Document Studio Report
curl --request POST \
--url https://api.n-3.co.uk/projects/{projectId}/document-studio/reports \
--header 'Content-Type: application/json' \
--data '
{
"reportName": "<string>",
"content": {
"blocks": [
{
"type": "<string>",
"content": "<string>",
"properties": {
"sectionId": "<string>",
"title": "<string>",
"required": true,
"fontSize": "<string>",
"textAlign": "<string>",
"color": "<string>"
},
"children": [
{}
]
}
],
"metadata": {
"templateId": "<string>",
"reportType": "<string>",
"author": "<string>",
"lastModified": "<string>"
}
}
}
'import requests
url = "https://api.n-3.co.uk/projects/{projectId}/document-studio/reports"
payload = {
"reportName": "<string>",
"content": {
"blocks": [
{
"type": "<string>",
"content": "<string>",
"properties": {
"sectionId": "<string>",
"title": "<string>",
"required": True,
"fontSize": "<string>",
"textAlign": "<string>",
"color": "<string>"
},
"children": [{}]
}
],
"metadata": {
"templateId": "<string>",
"reportType": "<string>",
"author": "<string>",
"lastModified": "<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({
reportName: '<string>',
content: {
blocks: [
{
type: '<string>',
content: '<string>',
properties: {
sectionId: '<string>',
title: '<string>',
required: true,
fontSize: '<string>',
textAlign: '<string>',
color: '<string>'
},
children: [{}]
}
],
metadata: {
templateId: '<string>',
reportType: '<string>',
author: '<string>',
lastModified: '<string>'
}
}
})
};
fetch('https://api.n-3.co.uk/projects/{projectId}/document-studio/reports', 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/projects/{projectId}/document-studio/reports",
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([
'reportName' => '<string>',
'content' => [
'blocks' => [
[
'type' => '<string>',
'content' => '<string>',
'properties' => [
'sectionId' => '<string>',
'title' => '<string>',
'required' => true,
'fontSize' => '<string>',
'textAlign' => '<string>',
'color' => '<string>'
],
'children' => [
[
]
]
]
],
'metadata' => [
'templateId' => '<string>',
'reportType' => '<string>',
'author' => '<string>',
'lastModified' => '<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/projects/{projectId}/document-studio/reports"
payload := strings.NewReader("{\n \"reportName\": \"<string>\",\n \"content\": {\n \"blocks\": [\n {\n \"type\": \"<string>\",\n \"content\": \"<string>\",\n \"properties\": {\n \"sectionId\": \"<string>\",\n \"title\": \"<string>\",\n \"required\": true,\n \"fontSize\": \"<string>\",\n \"textAlign\": \"<string>\",\n \"color\": \"<string>\"\n },\n \"children\": [\n {}\n ]\n }\n ],\n \"metadata\": {\n \"templateId\": \"<string>\",\n \"reportType\": \"<string>\",\n \"author\": \"<string>\",\n \"lastModified\": \"<string>\"\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/projects/{projectId}/document-studio/reports")
.header("Content-Type", "application/json")
.body("{\n \"reportName\": \"<string>\",\n \"content\": {\n \"blocks\": [\n {\n \"type\": \"<string>\",\n \"content\": \"<string>\",\n \"properties\": {\n \"sectionId\": \"<string>\",\n \"title\": \"<string>\",\n \"required\": true,\n \"fontSize\": \"<string>\",\n \"textAlign\": \"<string>\",\n \"color\": \"<string>\"\n },\n \"children\": [\n {}\n ]\n }\n ],\n \"metadata\": {\n \"templateId\": \"<string>\",\n \"reportType\": \"<string>\",\n \"author\": \"<string>\",\n \"lastModified\": \"<string>\"\n }\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.n-3.co.uk/projects/{projectId}/document-studio/reports")
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 \"reportName\": \"<string>\",\n \"content\": {\n \"blocks\": [\n {\n \"type\": \"<string>\",\n \"content\": \"<string>\",\n \"properties\": {\n \"sectionId\": \"<string>\",\n \"title\": \"<string>\",\n \"required\": true,\n \"fontSize\": \"<string>\",\n \"textAlign\": \"<string>\",\n \"color\": \"<string>\"\n },\n \"children\": [\n {}\n ]\n }\n ],\n \"metadata\": {\n \"templateId\": \"<string>\",\n \"reportType\": \"<string>\",\n \"author\": \"<string>\",\n \"lastModified\": \"<string>\"\n }\n }\n}"
response = http.request(request)
puts response.read_body{
"400": {},
"404": {},
"413": {},
"reportId": "<string>",
"version": 123
}Document Studio
Save Document Studio Report
Save or create a document studio report with rich content and automatic version control
POST
/
projects
/
{projectId}
/
document-studio
/
reports
Save Document Studio Report
curl --request POST \
--url https://api.n-3.co.uk/projects/{projectId}/document-studio/reports \
--header 'Content-Type: application/json' \
--data '
{
"reportName": "<string>",
"content": {
"blocks": [
{
"type": "<string>",
"content": "<string>",
"properties": {
"sectionId": "<string>",
"title": "<string>",
"required": true,
"fontSize": "<string>",
"textAlign": "<string>",
"color": "<string>"
},
"children": [
{}
]
}
],
"metadata": {
"templateId": "<string>",
"reportType": "<string>",
"author": "<string>",
"lastModified": "<string>"
}
}
}
'import requests
url = "https://api.n-3.co.uk/projects/{projectId}/document-studio/reports"
payload = {
"reportName": "<string>",
"content": {
"blocks": [
{
"type": "<string>",
"content": "<string>",
"properties": {
"sectionId": "<string>",
"title": "<string>",
"required": True,
"fontSize": "<string>",
"textAlign": "<string>",
"color": "<string>"
},
"children": [{}]
}
],
"metadata": {
"templateId": "<string>",
"reportType": "<string>",
"author": "<string>",
"lastModified": "<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({
reportName: '<string>',
content: {
blocks: [
{
type: '<string>',
content: '<string>',
properties: {
sectionId: '<string>',
title: '<string>',
required: true,
fontSize: '<string>',
textAlign: '<string>',
color: '<string>'
},
children: [{}]
}
],
metadata: {
templateId: '<string>',
reportType: '<string>',
author: '<string>',
lastModified: '<string>'
}
}
})
};
fetch('https://api.n-3.co.uk/projects/{projectId}/document-studio/reports', 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/projects/{projectId}/document-studio/reports",
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([
'reportName' => '<string>',
'content' => [
'blocks' => [
[
'type' => '<string>',
'content' => '<string>',
'properties' => [
'sectionId' => '<string>',
'title' => '<string>',
'required' => true,
'fontSize' => '<string>',
'textAlign' => '<string>',
'color' => '<string>'
],
'children' => [
[
]
]
]
],
'metadata' => [
'templateId' => '<string>',
'reportType' => '<string>',
'author' => '<string>',
'lastModified' => '<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/projects/{projectId}/document-studio/reports"
payload := strings.NewReader("{\n \"reportName\": \"<string>\",\n \"content\": {\n \"blocks\": [\n {\n \"type\": \"<string>\",\n \"content\": \"<string>\",\n \"properties\": {\n \"sectionId\": \"<string>\",\n \"title\": \"<string>\",\n \"required\": true,\n \"fontSize\": \"<string>\",\n \"textAlign\": \"<string>\",\n \"color\": \"<string>\"\n },\n \"children\": [\n {}\n ]\n }\n ],\n \"metadata\": {\n \"templateId\": \"<string>\",\n \"reportType\": \"<string>\",\n \"author\": \"<string>\",\n \"lastModified\": \"<string>\"\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/projects/{projectId}/document-studio/reports")
.header("Content-Type", "application/json")
.body("{\n \"reportName\": \"<string>\",\n \"content\": {\n \"blocks\": [\n {\n \"type\": \"<string>\",\n \"content\": \"<string>\",\n \"properties\": {\n \"sectionId\": \"<string>\",\n \"title\": \"<string>\",\n \"required\": true,\n \"fontSize\": \"<string>\",\n \"textAlign\": \"<string>\",\n \"color\": \"<string>\"\n },\n \"children\": [\n {}\n ]\n }\n ],\n \"metadata\": {\n \"templateId\": \"<string>\",\n \"reportType\": \"<string>\",\n \"author\": \"<string>\",\n \"lastModified\": \"<string>\"\n }\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.n-3.co.uk/projects/{projectId}/document-studio/reports")
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 \"reportName\": \"<string>\",\n \"content\": {\n \"blocks\": [\n {\n \"type\": \"<string>\",\n \"content\": \"<string>\",\n \"properties\": {\n \"sectionId\": \"<string>\",\n \"title\": \"<string>\",\n \"required\": true,\n \"fontSize\": \"<string>\",\n \"textAlign\": \"<string>\",\n \"color\": \"<string>\"\n },\n \"children\": [\n {}\n ]\n }\n ],\n \"metadata\": {\n \"templateId\": \"<string>\",\n \"reportType\": \"<string>\",\n \"author\": \"<string>\",\n \"lastModified\": \"<string>\"\n }\n }\n}"
response = http.request(request)
puts response.read_body{
"400": {},
"404": {},
"413": {},
"reportId": "<string>",
"version": 123
}Save a document studio report with rich formatting, dynamic content, and automatic version management. This endpoint creates a new version of the report each time it’s called, maintaining a complete version history.
Path Parameters
string
required
The unique identifier of the project associated with the report
Request Body
string
required
The name of the report. This serves as a unique identifier within the project scope.
object
required
The complete report content structure including blocks, formatting, and data
Show content structure
Show content structure
array
required
Array of content blocks that make up the report
Show block types
Show block types
string
required
Type of content block: “title”, “narrative”, “data”, “table”, “section”, “list”
string
The actual content of the block (for text-based blocks)
object
Block-specific properties and configuration
Show common properties
Show common properties
string
Unique identifier for the section (used for narrative blocks)
string
Display title for the block
boolean
Whether this block requires content (for templates)
string
Font size (e.g., “16px”, “1.2em”)
string
Text alignment: “left”, “center”, “right”, “justify”
string
Text color (hex code or CSS color name)
array
Child blocks (for section-type blocks)
Example Request
{
"reportName": "Q2 Progress Report",
"content": {
"blocks": [
{
"type": "title",
"content": "Quarterly Progress Report",
"properties": {
"fontSize": "24px",
"textAlign": "center",
"color": "#2c3e50"
}
},
{
"type": "section",
"properties": {
"title": "Executive Summary"
},
"children": [
{
"type": "narrative",
"properties": {
"sectionId": "executive-summary",
"title": "Project Overview",
"required": true
},
"content": "<p>The project has made significant progress during Q2 2024, with major milestones achieved in foundation work and structural development.</p>"
}
]
},
{
"type": "data",
"properties": {
"title": "Financial Summary",
"dataSource": "project.financials",
"format": "currency"
}
},
{
"type": "table",
"properties": {
"title": "Risk Assessment Summary",
"dataSource": "project.riskAssessments",
"columns": [
{"key": "category", "title": "Risk Category"},
{"key": "status", "title": "Current Status"},
{"key": "notes", "title": "Notes"}
]
}
},
{
"type": "list",
"properties": {
"sectionId": "key-achievements",
"title": "Key Achievements",
"listType": "bullet"
},
"content": "Foundation work completed ahead of schedule\nSteel frame installation commenced\nAll safety milestones met"
}
],
"metadata": {
"templateId": "template-001",
"reportType": "INTERIM",
"author": "Project Surveyor",
"lastModified": "2024-06-20T14:30:00.000Z"
}
}
}
Response
Returns the saved report information including the new version number:string
Unique identifier of the report
number
Version number of the newly created version
Example Response
{
"reportId": "report-12345",
"version": 3
}
Block Types Reference
Title Block
Used for report titles and major headings:{
"type": "title",
"content": "Report Title",
"properties": {
"fontSize": "24px",
"textAlign": "center",
"color": "#333333"
}
}
Narrative Block
For rich text content with editing capabilities:{
"type": "narrative",
"properties": {
"sectionId": "unique-section-id",
"title": "Section Title",
"required": true
},
"content": "<p>Rich HTML content with <strong>formatting</strong></p>"
}
Data Block
For dynamic project data integration:{
"type": "data",
"properties": {
"title": "Project Costs",
"dataSource": "project.costs.total",
"format": "currency",
"calculation": "sum"
}
}
Table Block
For structured data presentation:{
"type": "table",
"properties": {
"title": "Cost Breakdown",
"dataSource": "project.facilities",
"columns": [
{"key": "name", "title": "Facility"},
{"key": "budget", "title": "Budget", "format": "currency"},
{"key": "actual", "title": "Actual", "format": "currency"}
]
}
}
Section Block
For organizing content into logical sections:{
"type": "section",
"properties": {
"title": "Financial Analysis"
},
"children": [
// Child blocks go here
]
}
List Block
For bullet points and numbered lists:{
"type": "list",
"properties": {
"sectionId": "achievements",
"title": "Key Achievements",
"listType": "bullet"
},
"content": "Item 1\nItem 2\nItem 3"
}
Version Management
Document Studio automatically manages versions:- Auto-Increment: Each save creates a new version with incremented number
- Version History: Complete history is maintained for all versions
- No Overwrites: Previous versions are never lost or modified
- Timestamp Tracking: Each version includes creation timestamp
- User Attribution: Version changes are tracked by user
Content Validation
The system validates report content:- Block Structure: Ensures all blocks have required properties
- Data References: Validates that data sources exist and are accessible
- HTML Safety: Sanitizes HTML content in narrative blocks
- Required Fields: Checks that required narrative sections have content
- JSON Schema: Validates overall content structure against schema
Integration with Templates
Reports can be based on templates:- Template Inheritance: Reports inherit structure from templates
- Custom Modifications: Template-based reports can be customized
- Required Sections: Template requirements are enforced
- Dynamic Content: Template placeholders are populated with project data
Error Responses
error
Bad Request - Invalid content structure or missing required fields
{
"statusCode": 400,
"message": "Invalid block structure",
"error": "Bad Request"
}
error
Not Found - Project not found or user lacks access
{
"statusCode": 404,
"message": "Project not found",
"error": "Not Found"
}
error
Payload Too Large - Report content exceeds size limits
{
"statusCode": 413,
"message": "Report content too large",
"error": "Payload Too Large"
}
Best Practices
- Unique Section IDs: Use consistent, unique section IDs for narrative blocks
- Structured Content: Organize content logically using section blocks
- Data Integration: Leverage data blocks for dynamic project information
- Regular Saves: Save frequently to maintain version history
- Content Validation: Validate required sections before final save
- Template Consistency: Follow template structures when applicable
Related Endpoints
- Get Report - Retrieve a specific report version
- List Report Versions - View version history
- Export Report - Export as PDF

