Introduction
Certification Bodies API
External API for Approved Certification Bodies to manage product certification.
ID Format
ZDHC Sandbox uses a structured ID format: {prefix}-XXXXXXX-Z
| Prefix | Entity Type | Example |
|---|---|---|
01 |
Organisation | 01-XXXXXXX-Z |
20 |
Product | 20-XXXXXXX-Z |
40 |
InCheck Report | 40-XXXXXXX-Z |
Error Model
All non-2xx responses use a consistent error structure:
{
"error": {
"code": "string",
"message": "string",
"details": {}
}
}
Authenticating requests
To authenticate requests, include an Authorization header with the value "Bearer {YOUR_AUTH_KEY}".
All authenticated endpoints are marked with a requires authentication badge in the documentation below.
Retrieve a token by calling the /auth/login endpoint.
Certification Bodies/V1
CTZ Level
List CTZ levels
requires authentication
Returns a paginated list of CTZ levels for this certification body.
Example request:
curl --request GET \
--get "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/ctz-level?per_page=18&page=1&filter%5Bname%5D=quisquam&filter%5Bcreated_at%5D=%3C%3D+2026-07-01+10%3A59%3A25&filter%5Bupdated_at%5D=%3E%3D+2026-07-09+10%3A59%3A25&search=dicta&sort=name&column=name" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/ctz-level"
);
const params = {
"per_page": "18",
"page": "1",
"filter[name]": "quisquam",
"filter[created_at]": "<= 2026-07-01 10:59:25",
"filter[updated_at]": ">= 2026-07-09 10:59:25",
"search": "dicta",
"sort": "name",
"column": "name",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": [
{
"id": 1,
"name": "Foundational"
},
{
"id": 1,
"name": "Foundational"
}
],
"links": {
"first": "/?page=1",
"last": "/?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"links": [
{
"url": null,
"label": "« Previous",
"active": false
},
{
"url": "/?page=1",
"label": "1",
"active": true
},
{
"url": null,
"label": "Next »",
"active": false
}
],
"path": "/",
"per_page": 100,
"to": 2,
"total": 2
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
MRSL Standard
List MRSL standards
requires authentication
Returns a paginated list of MRSL standards for this certification body.
Example request:
curl --request GET \
--get "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/mrsl-standard?per_page=20&page=1&filter%5Bname%5D=rem&filter%5Bversion%5D=5&filter%5Bconformance_level_id%5D=3&filter%5Bconformance_level_name%5D=dolorem&filter%5Bstatus%5D=FAILED&filter%5Bstart_date%5D=%3D+2026-07-17+10%3A59%3A25&filter%5Bend_date%5D=%3C+2026-06-29+10%3A59%3A25&filter%5Bcreated_at%5D=%3E%3D+2026-07-01+10%3A59%3A25&filter%5Bupdated_at%5D=%3E%3D+2026-06-29+10%3A59%3A25&search=minima&sort=name&column=name" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/mrsl-standard"
);
const params = {
"per_page": "20",
"page": "1",
"filter[name]": "rem",
"filter[version]": "5",
"filter[conformance_level_id]": "3",
"filter[conformance_level_name]": "dolorem",
"filter[status]": "FAILED",
"filter[start_date]": "= 2026-07-17 10:59:25",
"filter[end_date]": "< 2026-06-29 10:59:25",
"filter[created_at]": ">= 2026-07-01 10:59:25",
"filter[updated_at]": ">= 2026-06-29 10:59:25",
"search": "minima",
"sort": "name",
"column": "name",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": [
{
"id": 1,
"reference_id": "30-HRBQFLXEEXU-K",
"name": "Brachi Testing Services",
"version": "ZDHC MRSL v2.0",
"start_date": "2020-08-12T00:00:00.000000Z",
"end_date": "2024-06-01T00:00:00.000000Z",
"status": "PASSED",
"conformance_level_id": 1,
"conformance_level_name": "Level 1"
},
{
"id": 1,
"reference_id": "30-HRBQFLXEEXU-K",
"name": "Brachi Testing Services",
"version": "ZDHC MRSL v2.0",
"start_date": "2020-08-12T00:00:00.000000Z",
"end_date": "2024-06-01T00:00:00.000000Z",
"status": "PASSED",
"conformance_level_id": 1,
"conformance_level_name": "Level 1"
}
],
"links": {
"first": "/?page=1",
"last": "/?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"links": [
{
"url": null,
"label": "« Previous",
"active": false
},
{
"url": "/?page=1",
"label": "1",
"active": true
},
{
"url": null,
"label": "Next »",
"active": false
}
],
"path": "/",
"per_page": 100,
"to": 2,
"total": 2
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Product Assignment
List product assignments
requires authentication
Returns a paginated list of product assignments for this certification body.
Example request:
curl --request GET \
--get "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/product-assignment?per_page=8&page=1&filter%5Bproduct_id%5D=19&filter%5Bproduct_reference_id%5D=repudiandae&filter%5Bproduct_name%5D=et&filter%5Bproduct_alternate_names%5D=quasi&filter%5Bassignment_status%5D=UNDER_REVIEW&filter%5Bformulator_id%5D=6&filter%5Bformulator_reference_id%5D=quam&filter%5Bformulator_name%5D=officiis&filter%5Bmrsl_level_id%5D=3&filter%5Bctz_level_id%5D=17&filter%5Bassigned_at%5D=%3D+2026-07-07+10%3A59%3A25&filter%5Bupdated_at%5D=%3E%3D+2026-07-13+10%3A59%3A25&filter%5Bproduct_use_types_id%5D=11&filter%5Bproduct_categories_id%5D=16&search=est&sort=id&column=id" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/product-assignment"
);
const params = {
"per_page": "8",
"page": "1",
"filter[product_id]": "19",
"filter[product_reference_id]": "repudiandae",
"filter[product_name]": "et",
"filter[product_alternate_names]": "quasi",
"filter[assignment_status]": "UNDER_REVIEW",
"filter[formulator_id]": "6",
"filter[formulator_reference_id]": "quam",
"filter[formulator_name]": "officiis",
"filter[mrsl_level_id]": "3",
"filter[ctz_level_id]": "17",
"filter[assigned_at]": "= 2026-07-07 10:59:25",
"filter[updated_at]": ">= 2026-07-13 10:59:25",
"filter[product_use_types_id]": "11",
"filter[product_categories_id]": "16",
"search": "est",
"sort": "id",
"column": "id",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": [
{
"id": null,
"product_id": 1,
"product_reference_id": "20-TZDRC62ZX2PA-B",
"product_name": "A-POLE G-2 [P214AG76]",
"product_description": null,
"product_alternate_names": [
"P214AG76"
],
"formulator_id": 470,
"formulator_reference_id": "01-QAX9HUTDPHX-G",
"formulator_name": "JiangYin Xishiqiao Auxiliary Factory",
"assignment_status": null,
"mrsl_level_id": null,
"mrsl_level_name": null,
"ctz_level_id": null,
"ctz_level_name": null,
"assigned_at": null,
"updated_at": null
},
{
"id": null,
"product_id": 1,
"product_reference_id": "20-TZDRC62ZX2PA-B",
"product_name": "A-POLE G-2 [P214AG76]",
"product_description": null,
"product_alternate_names": [
"P214AG76"
],
"formulator_id": 470,
"formulator_reference_id": "01-QAX9HUTDPHX-G",
"formulator_name": "JiangYin Xishiqiao Auxiliary Factory",
"assignment_status": null,
"mrsl_level_id": null,
"mrsl_level_name": null,
"ctz_level_id": null,
"ctz_level_name": null,
"assigned_at": null,
"updated_at": null
}
],
"links": {
"first": "/?page=1",
"last": "/?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"links": [
{
"url": null,
"label": "« Previous",
"active": false
},
{
"url": "/?page=1",
"label": "1",
"active": true
},
{
"url": null,
"label": "Next »",
"active": false
}
],
"path": "/",
"per_page": 100,
"to": 2,
"total": 2
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Bulk-create product assignment certifications
requires authentication
Each row in certifications creates one new MRSL+CTZ certification pair on the product assignment
identified by assignment_id. Existing certifications on an assignment are not modified or removed.
Multiple rows may reference the same assignment_id; each row adds another certification pair.
The response data summarizes by unique assignment_id: submitted_count is the number of distinct
assignment IDs in the request; created_count and created_ids count assignments where at least one
row was created successfully. Per-row failures are listed in errors.
Example request:
curl --request POST \
"https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/product-assignment/bulk-store" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"certifications\": [
{
\"certificate_number\": \"1234567890\",
\"certificate_result\": \"Pass\",
\"certificate_issue_date\": \"2026-01-01\",
\"certificate_end_date\": \"2026-01-01\",
\"assignment_id\": 1,
\"mrsl_standard_id\": 1,
\"ctz_level_id\": 1,
\"safety_data_sheet_id\": 1
}
]
}"
const url = new URL(
"https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/product-assignment/bulk-store"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"certifications": [
{
"certificate_number": "1234567890",
"certificate_result": "Pass",
"certificate_issue_date": "2026-01-01",
"certificate_end_date": "2026-01-01",
"assignment_id": 1,
"mrsl_standard_id": 1,
"ctz_level_id": 1,
"safety_data_sheet_id": 1
}
]
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, Every distinct assignment ID in the request received at least one new certification.):
{
"message": "Product assignment certifications created successfully",
"data": {
"submitted_count": 2,
"created_count": 2,
"created_ids": [
101,
102
],
"not_createable_count": 0,
"errors": []
}
}
Example response (200, Some assignment IDs could not receive new certifications (e.g. declined assignment); failed rows appear under `errors`. Same response shape as full success.):
{
"message": "Product assignment certifications partially created",
"data": {
"submitted_count": 2,
"created_count": 1,
"created_ids": [
101
],
"not_createable_count": 1,
"errors": [
{
"assignment_id": 102,
"error": "Product assignment is already declined"
}
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Bulk-decline product assignments
requires authentication
Marks several assignments as declined in one request. Assignments that are already declined are skipped.
The response data is a summary object (counts and IDs), not a product-assignment API resource collection.
Example request:
curl --request POST \
"https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/product-assignment/bulk-decline" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"assignment_ids\": [
101
],
\"reason\": \"Unable to process at this time.\"
}"
const url = new URL(
"https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/product-assignment/bulk-decline"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"assignment_ids": [
101
],
"reason": "Unable to process at this time."
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, All submitted IDs were eligible and are now declined.):
{
"message": "Product assignments declined successfully",
"data": {
"submitted_count": 2,
"declined_count": 2,
"declined_ids": [
101,
102
],
"already_declined_count": 0,
"already_declined_ids": []
}
}
Example response (200, Some IDs were already declined; they are listed under `already_declined_ids` (same response shape).):
{
"message": "Product assignments partially declined",
"data": {
"submitted_count": 2,
"declined_count": 1,
"declined_ids": [
101
],
"already_declined_count": 1,
"already_declined_ids": [
102
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create a product assignment certification
requires authentication
Creates one MRSL certification together with its linked CTZ certification on the given assignment.
Example request:
curl --request POST \
"https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/product-assignment/1" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"certificate_number\": \"1234567890\",
\"certificate_result\": \"Pass\",
\"certificate_issue_date\": \"2026-01-01\",
\"certificate_end_date\": \"2026-01-01\",
\"mrsl_standard_id\": 1,
\"ctz_level_id\": 1,
\"safety_data_sheet_id\": 1
}"
const url = new URL(
"https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/product-assignment/1"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"certificate_number": "1234567890",
"certificate_result": "Pass",
"certificate_issue_date": "2026-01-01",
"certificate_end_date": "2026-01-01",
"mrsl_standard_id": 1,
"ctz_level_id": 1,
"safety_data_sheet_id": 1
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"data": {
"id": 1,
"assignment_status": "ACCEPTED",
"product": {
"id": 212878,
"reference_id": "20-4G9DTFRJWQ72-I",
"name": "REACTOBOND YELLOW RNL 150% [P397IA55]",
"alternate_names": [
"P397IA55"
],
"description": null,
"version": 1,
"status": "PUBLISHED",
"formulator": {
"id": 6267,
"name": "Meghmani Dyes and Intermediates LLP",
"reference_id": "01-76N8M6UUCZG-Y"
},
"safety_data_sheets": [
{
"id": 84327,
"file_name": "MSDS YELLOW RNL 150%.pdf",
"version": 1,
"locale": "en",
"uploaded_by": {
"id": 6267,
"name": "Meghmani Dyes and Intermediates LLP",
"reference_id": "01-76N8M6UUCZG-Y"
},
"file_url": null
}
],
"sds_url": null,
"website_url": null
},
"current_max_mrsl_certification": null,
"current_max_ctz_certification": null,
"mrsl_certifications": [],
"assigned_at": "2026-05-14T19:42:10.000000Z",
"updated_at": "2026-05-14T19:42:10.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Decline a product assignment
requires authentication
Marks the assignment identified in the URL as declined for this certification body.
Example request:
curl --request POST \
"https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/product-assignment/1/decline" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"reason\": \"Unable to process at this time.\"
}"
const url = new URL(
"https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/product-assignment/1/decline"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"reason": "Unable to process at this time."
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"data": {
"id": 1,
"assignment_status": "ACCEPTED",
"product": {
"id": 212878,
"reference_id": "20-4G9DTFRJWQ72-I",
"name": "REACTOBOND YELLOW RNL 150% [P397IA55]",
"alternate_names": [
"P397IA55"
],
"description": null,
"version": 1,
"status": "PUBLISHED",
"formulator": {
"id": 6267,
"name": "Meghmani Dyes and Intermediates LLP",
"reference_id": "01-76N8M6UUCZG-Y"
},
"safety_data_sheets": [
{
"id": 84327,
"file_name": "MSDS YELLOW RNL 150%.pdf",
"version": 1,
"locale": "en",
"uploaded_by": {
"id": 6267,
"name": "Meghmani Dyes and Intermediates LLP",
"reference_id": "01-76N8M6UUCZG-Y"
},
"file_url": null
}
],
"sds_url": null,
"website_url": null
},
"current_max_mrsl_certification": null,
"current_max_ctz_certification": null,
"mrsl_certifications": [],
"assigned_at": "2026-05-14T19:42:10.000000Z",
"updated_at": "2026-05-14T19:42:10.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Get a product assignment
requires authentication
Returns one assignment, including related certification and product data.
Example request:
curl --request GET \
--get "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/product-assignment/1" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/product-assignment/1"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
{
"data": {
"id": 1,
"assignment_status": "ACCEPTED",
"product": {
"id": 212878,
"reference_id": "20-4G9DTFRJWQ72-I",
"name": "REACTOBOND YELLOW RNL 150% [P397IA55]",
"alternate_names": [
"P397IA55"
],
"description": null,
"version": 1,
"status": "PUBLISHED",
"formulator": {
"id": 6267,
"name": "Meghmani Dyes and Intermediates LLP",
"reference_id": "01-76N8M6UUCZG-Y"
},
"safety_data_sheets": [
{
"id": 84327,
"file_name": "MSDS YELLOW RNL 150%.pdf",
"version": 1,
"locale": "en",
"uploaded_by": {
"id": 6267,
"name": "Meghmani Dyes and Intermediates LLP",
"reference_id": "01-76N8M6UUCZG-Y"
},
"file_url": null
}
],
"sds_url": null,
"website_url": null
},
"current_max_mrsl_certification": null,
"current_max_ctz_certification": null,
"mrsl_certifications": [],
"assigned_at": "2026-05-14T19:42:10.000000Z",
"updated_at": "2026-05-14T19:42:10.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Download a safety data sheet
requires authentication
Returns the SDS file for the chemical product linked to the given assignment.
Example request:
curl --request GET \
--get "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/product-assignment/hic/safety-data-sheet/1" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/1/product-assignment/hic/safety-data-sheet/1"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
file
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.