Skip to main content

Understanding management systems in ISO 14001

ISO 14001 is the international standard for Environmental Management Systems (EMS). Beyond measuring emissions, it requires organizations to actively manage environmental risks, track nonconformities, define improvement objectives, and close corrective actions — creating a continuous improvement loop. Dcycle’s Management Systems module maps directly to the ISO 14001 Plan-Do-Check-Act (PDCA) cycle:
┌─────────────────────────────────────────────────────────────────────────────┐
│                   ISO 14001 MANAGEMENT SYSTEMS IN DCYCLE                    │
├──────────────────────┬──────────────────────────────────────────────────────┤
│  PDCA Phase          │  Dcycle Resources                                    │
├──────────────────────┼──────────────────────────────────────────────────────┤
│  PLAN                │  Risks & Opportunities  → identify and assess        │
│  (Clause 6)          │  Objectives             → set measurable targets     │
├──────────────────────┼──────────────────────────────────────────────────────┤
│  DO                  │  Actions                → implement measures         │
│  (Clause 8)          │  (corrective, preventive, improvement)               │
├──────────────────────┼──────────────────────────────────────────────────────┤
│  CHECK               │  Nonconformities        → detect deviations          │
│  (Clause 9)          │  Dashboard              → monitor KPIs               │
├──────────────────────┼──────────────────────────────────────────────────────┤
│  ACT                 │  Actions                → close and verify           │
│  (Clause 10)         │  effectiveness of corrective actions                 │
└──────────────────────┴──────────────────────────────────────────────────────┘
All management system resources are scoped to a Project.Every endpoint uses /management-systems/projects/{project_id}/.... A project represents an ISO 14001 certification scope (e.g., a facility, a business unit, or the entire organization). Retrieve your project_id from the Projects API before proceeding.

Prerequisites

Before starting, ensure you have:
  • Dcycle API credentials (get them here)
  • A valid project_id for the ISO 14001 scope you are managing
  • Your organization_id (returned alongside the project)
Using the Dcycle App?You can manage risks, nonconformities, and objectives directly in the app at app.dcycle.io under Management Systems. The API is the integration layer — use it to sync from your own systems or automate workflows.

Data map: management system resources overview

┌────────────────────────────────────────────────────────────────────────────────────┐
│                    MANAGEMENT SYSTEMS DATA REQUIREMENTS                             │
├────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                    │
│  ┌──────────────────────────────────────────────────────────────────────────────┐  │
│  │ Risks & Opportunities  (Step 1)                                              │  │
│  ├──────────────────────────────────────────────────────────────────────────────┤  │
│  │  Required                     Optional                                       │  │
│  │  ─────────────────────         ──────────────────────                        │  │
│  │  • type (risk/opportunity)     • description                                 │  │
│  │  • title                       • source                                      │  │
│  │                                • iso_clause                                  │  │
│  │                                • probability_level (1-5)                     │  │
│  │                                • impact_level (1-5)                          │  │
│  │                                • owner_user_id                               │  │
│  │                                • review_date                                 │  │
│  │                                • facility_id / is_transversal                │  │
│  └──────────────────────────────────────────────────────────────────────────────┘  │
│                                                                                    │
│  ┌──────────────────────────────────────────────────────────────────────────────┐  │
│  │ Nonconformities  (Step 2)                                                    │  │
│  ├──────────────────────────────────────────────────────────────────────────────┤  │
│  │  Required                     Optional                                       │  │
│  │  ─────────────────────         ──────────────────────                        │  │
│  │  • type (nonconformity/        • severity (minor/major/critical)             │  │
│  │    incident/observation)       • source, iso_clause, location                │  │
│  │  • title                       • detected_date, detected_by_user_id         │  │
│  │                                • root_cause, immediate_actions               │  │
│  │                                • area_causante, area_detectora               │  │
│  │                                • cost, facility_id                           │  │
│  └──────────────────────────────────────────────────────────────────────────────┘  │
│                                                                                    │
│  ┌──────────────────────────────────────────────────────────────────────────────┐  │
│  │ Objectives  (Step 3)                                                         │  │
│  ├──────────────────────────────────────────────────────────────────────────────┤  │
│  │  Required                     Optional                                       │  │
│  │  ─────────────────────         ──────────────────────                        │  │
│  │  • title                       • target_value + current_value + unit         │  │
│  │                                • responsible_user_id                         │  │
│  │                                • start_date, end_date                        │  │
│  └──────────────────────────────────────────────────────────────────────────────┘  │
│                                                                                    │
│  ┌──────────────────────────────────────────────────────────────────────────────┐  │
│  │ Actions  (Step 4)                                                            │  │
│  ├──────────────────────────────────────────────────────────────────────────────┤  │
│  │  Required                     Optional                                       │  │
│  │  ─────────────────────         ──────────────────────                        │  │
│  │  • source_type                 • description, responsible_user_id(s)         │  │
│  │  • source_id                   • deadline, cost                              │  │
│  │  • action_type                 • effectiveness_verified + notes              │  │
│  │  • title                                                                     │  │
│  └──────────────────────────────────────────────────────────────────────────────┘  │
│                                                                                    │
└────────────────────────────────────────────────────────────────────────────────────┘

Workflow overview

1

Identify risks and opportunities

Register environmental risks and opportunities for your project. Dcycle auto-assigns a sequential code (e.g., R-001, O-001) and computes a risk level from probability × impact.
2

Log nonconformities and incidents

Record deviations, incidents, or observations detected during audits or operations. Attach evidence files as needed.
3

Define environmental objectives

Set measurable targets linked to the project scope (e.g., “Reduce water consumption by 15%”). Track progress with current_value vs. target_value.
4

Create and assign actions

Link corrective, preventive, or improvement actions to a risk, opportunity, or nonconformity. Assign responsible users and deadlines.
5

Monitor via dashboard

Pull aggregated KPIs — open risks by level, nonconformity severity distribution, overdue actions — for management review.

Step 1: Risks and opportunities

Emission sources covered

TypeCode prefixWhen to use
riskR-001Environmental threats (regulatory, operational, climate)
opportunityO-001Improvement areas (efficiency, new practices, certifications)

Risk scoring

Dcycle uses a three-phase scoring model for risks: inherent, mitigation, and residual.

Inherent risk

risk_score = probability_level × impact_level

risk_level:
  1–4   → low
  5–9   → medium
  10–16 → high
  17–25 → critical

Mitigation coefficients (risks only)

Optionally provide mitigation_probability and mitigation_impact — decimal coefficients between 0.00 and 1.00 representing how much each dimension is reduced by controls in place. Both must be provided together.

Residual risk (computed)

When both mitigation coefficients are provided, Dcycle computes:
residual_probability = probability_level × mitigation_probability
residual_impact      = impact_level × mitigation_impact
residual_risk_score  = residual_probability × residual_impact
residual_risk_level  → same threshold table as inherent
The dashboard and list filters use residual risk level when available, falling back to inherent risk level when no mitigation is set.
FieldTypeRequiredDescriptionExample
typestring"risk" or "opportunity""risk"
titlestringShort title (max 500 chars)"Regulatory non-compliance risk"
descriptionstringDetailed description"Risk of CBAM penalty if..."
sourcestringWhere it was identified"Internal audit Q1-2026"
iso_clausestringISO 14001 clause reference"6.1.2"
probability_levelinteger1 (low) to 5 (high)3
impact_levelinteger1 (low) to 5 (high)4
mitigation_probabilitydecimalMitigation coefficient for probability (0.00–1.00). Risks only. Must be paired with mitigation_impact.0.50
mitigation_impactdecimalMitigation coefficient for impact (0.00–1.00). Risks only. Must be paired with mitigation_probability.0.40
statusstringDefault: "open". Also: "in_progress", "closed""open"
owner_user_idUUIDResponsible user"a8315ef3-..."
review_datedateNext review date"2026-09-30"
facility_idUUIDScope to a specific facility"b9c2..."
is_transversalbooleanApplies across all companies. Default: falsefalse
Where to get this data:
  • project_id: Projects API → GET /v1/projects
  • owner_user_id: Members API → GET /v1/members
  • facility_id: Facilities API → GET /v1/facilities
import requests
import os

headers = {
    "Authorization": f"Bearer {os.getenv('DCYCLE_API_KEY')}",
    "Content-Type": "application/json",
    "x-organization-id": os.getenv("DCYCLE_ORG_ID"),
}

project_id = "your-project-uuid"

# Create a risk with inherent scoring and mitigation
risk = {
    "type": "risk",
    "title": "Risk of permit violation due to increased waste generation",
    "source": "Internal audit Q1-2026",
    "iso_clause": "6.1.2",
    "probability_level": 3,
    "impact_level": 4,
    "mitigation_probability": 0.50,
    "mitigation_impact": 0.40,
    "status": "open",
    "review_date": "2026-09-30",
}

response = requests.post(
    f"https://api.dcycle.io/api/v1/management-systems/projects/{project_id}/risks-opportunities",
    headers=headers,
    json=risk,
)

result = response.json()
print(f"✅ Risk created: {result['code']} (inherent: {result['risk_score']}, residual: {result['residual_risk_score']}, level: {result['residual_risk_level']})")

List and filter risks

# Filter by type and risk level
response = requests.get(
    f"https://api.dcycle.io/api/v1/management-systems/projects/{project_id}/risks-opportunities",
    headers=headers,
    params={
        "type": "risk",
        "risk_level": "high",
        "status": "open",
        "page": 1,
        "size": 50,
    },
).json()

print(f"📊 Open high-risks: {response['total']}")
for item in response["items"]:
    print(f"   {item['code']} - {item['title']} (score: {item['risk_score']})")
Transversal vs. facility-scoped risksUse is_transversal: true for organization-wide risks (e.g., a regulatory change affecting all sites). Use facility_id to scope a risk to a single facility. Both are mutually exclusive: if is_transversal is true, facility_id should be null.

Step 2: Nonconformities, incidents, and observations

Dcycle uses a single endpoint for all three types of deviation records. The type field distinguishes them:
TypeCode prefixISO 14001 context
nonconformityNC-001Failure to meet a requirement (Clause 10.2)
incidentINC-001Environmental incident or near-miss
observationOBS-001Deviation that does not yet qualify as a nonconformity
FieldTypeRequiredDescriptionExample
typestring"nonconformity", "incident", or "observation""nonconformity"
titlestringShort title (max 500 chars)"Waste segregation procedure not followed"
severitystring"minor", "major", or "critical""major"
sourcestringWhere detected"External audit ISO 14001"
iso_clausestringISO clause reference"8.1"
detected_datedateDetection date"2026-04-10"
detected_by_user_idUUIDDcycle user who detected it"c3d4..."
detected_by_namestringName if not a Dcycle user"External Auditor"
root_causestringRoot cause analysis"Lack of training"
locationstringWhere it happened"Warehouse B - sorting area"
immediate_actionsstringActions taken on the spot"Area cordoned off and waste re-sorted"
area_causantestringCausing department"Operations"
area_detectorastringDetecting department"Quality & Environment"
costdecimalAssociated cost (in org currency)"1500.00"
facility_idUUIDScope to a specific facility"b9c2..."
# Log a nonconformity detected during an external audit
nc = {
    "type": "nonconformity",
    "title": "Waste segregation procedure not followed in Warehouse B",
    "severity": "major",
    "source": "External ISO 14001 audit",
    "iso_clause": "8.1",
    "detected_date": "2026-04-10",
    "detected_by_name": "External Auditor - Bureau Veritas",
    "root_cause": "Lack of refresher training for new operators",
    "location": "Warehouse B - sorting area",
    "area_causante": "Operations",
    "area_detectora": "Quality & Environment",
}

response = requests.post(
    f"https://api.dcycle.io/api/v1/management-systems/projects/{project_id}/nonconformities",
    headers=headers,
    json=nc,
)

result = response.json()
print(f"✅ Nonconformity logged: {result['code']} (severity: {result['severity']})")
nonconformity_id = result["id"]

Attach evidence files

Nonconformities support file attachments (audit reports, photos, etc.) via a two-step presigned URL flow:
# Step 1: Get a presigned S3 upload URL
presigned = requests.post(
    f"https://api.dcycle.io/api/v1/management-systems/projects/{project_id}/nonconformities/{nonconformity_id}/attachments/presigned-url",
    headers=headers,
    json={"file_name": "audit-report.pdf", "content_type": "application/pdf"},
).json()

# Step 2: Upload directly to S3 (no auth headers for the S3 PUT)
with open("audit-report.pdf", "rb") as f:
    requests.put(presigned["upload_url"], data=f, headers={"Content-Type": "application/pdf"})

# Step 3: Register the attachment in Dcycle
requests.post(
    f"https://api.dcycle.io/api/v1/management-systems/projects/{project_id}/nonconformities/{nonconformity_id}/attachments",
    headers=headers,
    json={"file_name": "audit-report.pdf", "file_id": presigned["file_id"]},
)
print("✅ Attachment registered")
File names must not contain path separators.The API rejects file names with /, \, or .. to prevent path traversal. Use flat names like audit-report-2026.pdf.

Step 3: Environmental objectives

Objectives let you define measurable environmental targets and track progress over time. Dcycle auto-assigns codes like OBJ-001.
FieldTypeRequiredDescriptionExample
titlestringObjective title (max 500 chars)"Reduce energy consumption by 10%"
descriptionstringAdditional context"Aligned with ISO 14001 clause 6.2"
responsible_user_idUUIDResponsible user"d5e6..."
start_datedateStart of measurement period"2026-01-01"
end_datedateTarget completion date"2026-12-31"
statusstringDefault: "open". Also: "in_progress", "achieved", "not_achieved""in_progress"
target_valuedecimalTarget metric value"90"
current_valuedecimalCurrent metric value (updated over time)"95"
unitstringUnit of measurement"MWh"
objective = {
    "title": "Reduce electricity consumption by 10% vs. 2025 baseline",
    "description": "Aligned with ISO 14001 clause 6.2 and energy efficiency plan",
    "start_date": "2026-01-01",
    "end_date": "2026-12-31",
    "target_value": "900",
    "current_value": "1000",
    "unit": "MWh",
    "status": "in_progress",
}

response = requests.post(
    f"https://api.dcycle.io/api/v1/management-systems/projects/{project_id}/objectives",
    headers=headers,
    json=objective,
)

result = response.json()
print(f"✅ Objective created: {result['code']} - {result['title']}")
objective_id = result["id"]

Update progress

Use PATCH to update current_value as measurements come in:
# Update current consumption reading at end of Q1
requests.patch(
    f"https://api.dcycle.io/api/v1/management-systems/projects/{project_id}/objectives/{objective_id}",
    headers=headers,
    json={"current_value": "970"},
)
print("✅ Objective progress updated")

Step 4: Actions

Actions are the operational core of the management system. Every action must be linked to a source: a risk, an opportunity, or a nonconformity.
action_typePurpose
immediateStop-gap measure taken on the spot
correctiveEliminate root cause of a nonconformity
preventiveAvoid a potential nonconformity or risk
improvementEnhance a process beyond minimum requirements
FieldTypeRequiredDescriptionExample
source_typestring"risk", "opportunity", or "nonconformity""nonconformity"
source_idUUIDID of the risk, opportunity, or nonconformity"e7f8..."
action_typestring"immediate", "corrective", "preventive", "improvement""corrective"
titlestringAction title (max 500 chars)"Deliver waste segregation training"
descriptionstringDetailed steps"Mandatory 2h session for all operators"
responsible_user_idUUIDPrimary responsible user"f9a0..."
responsible_user_idsUUID[]Multiple responsible users (max 50)["f9a0...", "b1c2..."]
deadlinedateTarget completion date"2026-05-15"
statusstringDefault: "open". Also: "in_progress", "completed", "cancelled""open"
costdecimalEstimated cost"800.00"
action = {
    "source_type": "nonconformity",
    "source_id": nonconformity_id,
    "action_type": "corrective",
    "title": "Deliver mandatory waste segregation refresher training",
    "description": "2-hour session for all Operations staff. Attendance to be recorded.",
    "deadline": "2026-05-15",
    "status": "open",
    "cost": "800.00",
}

response = requests.post(
    f"https://api.dcycle.io/api/v1/management-systems/projects/{project_id}/actions",
    headers=headers,
    json=action,
)

result = response.json()
print(f"✅ Action created: {result['code']} (source: {result['source_code']})")
action_id = result["id"]

Close and verify effectiveness

When the action is completed, mark it as done and record effectiveness verification — required by ISO 14001 Clause 10.2:
requests.patch(
    f"https://api.dcycle.io/api/v1/management-systems/projects/{project_id}/actions/{action_id}",
    headers=headers,
    json={
        "status": "completed",
        "completion_date": "2026-05-12",
        "effectiveness_verified": True,
        "effectiveness_notes": "All 18 operators attended. Follow-up audit confirmed correct segregation.",
    },
)
print("✅ Action closed with effectiveness verification")
Actions are linked to their source automatically.When you retrieve a nonconformity or risk via the GET /{id} endpoint, the response includes a nested actions array — no separate join needed.

Step 5: Monitor via dashboard

Pull a real-time summary of the project’s management system health:
dashboard = requests.get(
    f"https://api.dcycle.io/api/v1/management-systems/projects/{project_id}/dashboard",
    headers=headers,
).json()

risks = dashboard["risks"]
ncs = dashboard["nonconformities"]
actions = dashboard["actions"]

print(f"📊 Management System Dashboard — Project {project_id}")
print(f"   Risks total: {risks['total']}  |  by level: {risks['by_level']}")
print(f"   Nonconformities: {ncs['total']}  |  by severity: {ncs['by_severity']}")
print(f"   Actions: {actions['total']}  |  overdue: {actions['overdue_count']}")
print(f"   Corrective actions by status: {actions['corrective_by_status']}")

Dashboard response schema

FieldTypeDescription
risks.totalintegerTotal risks for the project
risks.by_levelobjectCount per level: low, medium, high, critical
opportunities.totalintegerTotal opportunities
opportunities.by_statusobjectCount per status
nonconformities.totalintegerTotal nonconformities + incidents + observations
nonconformities.by_statusobjectCount per status
nonconformities.by_severityobjectCount per severity
nonconformities.by_area_causanteobjectCount per causing department
actions.totalintegerTotal actions
actions.overdue_countintegerActions past deadline with status not completed
actions.corrective_by_statusobjectCorrective actions count by status

Auto-generated codes

Every resource gets a sequential, human-readable code automatically:
ResourceCode formatExample
RiskR-{sequence}R-001, R-012
OpportunityO-{sequence}O-001
NonconformityNC-{sequence}NC-001
IncidentINC-{sequence}INC-003
ObservationOBS-{sequence}OBS-007
ObjectiveOBJ-{sequence}OBJ-001
ActionDerived from sourceNC-001/AC-001
Sequences are per-organization for risks/opportunities/objectives, and per-project for nonconformities.
Use code in audit reports and external documents — it stays stable even if the UUID is not convenient for human readers. Filter by code using the list endpoints’ search params.

Projects API

Retrieve your project IDs and organization scope

Members API

Look up user IDs for owner and responsible fields

Facilities API

Scope risks and nonconformities to specific facilities

Authentication guide

Set up API keys and organization headers