MENU navbar-image

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.

Every request must also include the Auth-Organisation-Id header with your certification body's organisation reference ID (prefix 01, e.g. 01-4SWZLM6LU9C-J). The header is included in the example requests for each endpoint below.

Certification Bodies/V1

Assigned Products

List assigned products

requires authentication

Returns a paginated list of assigned products for this certification body.

Example request:
curl --request GET \
    --get "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/assigned-products?per_page=10&page=1&filter%5Bproduct_reference_id%5D=labore&filter%5Bproduct_name%5D=aliquam&filter%5Bformulator_reference_id%5D=sequi&filter%5Bformulator_name%5D=dolores&filter%5Bassigned_by%5D=odit&filter%5Bassignment_status%5D=UNDER_REVIEW&filter%5Bassigned_at%5D=%3C%3D+2026-08-26+14%3A29%3A40&search=ipsam&sort=product_reference_id" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"per_page\": 24,
    \"search\": \"bhzpayhaccjosflqusjfaakrboyihwqnnnkhrqxryvhegdxriakrjz\"
}"
const url = new URL(
    "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/assigned-products"
);

const params = {
    "per_page": "10",
    "page": "1",
    "filter[product_reference_id]": "labore",
    "filter[product_name]": "aliquam",
    "filter[formulator_reference_id]": "sequi",
    "filter[formulator_name]": "dolores",
    "filter[assigned_by]": "odit",
    "filter[assignment_status]": "UNDER_REVIEW",
    "filter[assigned_at]": "<= 2026-08-26 14:29:40",
    "search": "ipsam",
    "sort": "product_reference_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",
};

let body = {
    "per_page": 24,
    "search": "bhzpayhaccjosflqusjfaakrboyihwqnnnkhrqxryvhegdxriakrjz"
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "data": [
        {
            "product_reference_id": null,
            "product_name": null,
            "formulator_reference_id": null,
            "formulator_name": null,
            "assigned_by": null,
            "assigned_at": "2026-08-20",
            "assignment_status": null
        },
        {
            "product_reference_id": null,
            "product_name": null,
            "formulator_reference_id": null,
            "formulator_name": null,
            "assigned_by": null,
            "assigned_at": "2026-08-20",
            "assignment_status": 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": "&laquo; Previous",
                "active": false
            },
            {
                "url": "/?page=1",
                "label": "1",
                "active": true
            },
            {
                "url": null,
                "label": "Next &raquo;",
                "active": false
            }
        ],
        "path": "/",
        "per_page": 50,
        "to": 2,
        "total": 2
    }
}
 

Example response (200):


Success.
 

Example response (401):


Token not found
 

Example response (403):


Authenticated Organisation is not one of types ZDHC MRSL Certification Bodies
 

Example response (403):


User does not have required permission.
 

Example response (422):


Validation error
 

Request      

GET api/certification-bodies/v1/assigned-products

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

per_page   integer  optional    

Number of items to show per page. Defaults to 50 Example: 10

page   integer  optional    

the page number to show. Example: 1

filter[product_reference_id]   string  optional    

Filter column product_reference_id by any accepted value. Filter by product reference ID Example: labore

filter[product_name]   string  optional    

Filter column product_name by any accepted value. Filter by product name Example: aliquam

filter[formulator_reference_id]   string  optional    

Filter column formulator_reference_id by any accepted value. Filter by formulator reference ID Example: sequi

filter[formulator_name]   string  optional    

Filter column formulator_name by any accepted value. Filter by formulator name Example: dolores

filter[assigned_by]   string  optional    

Filter column assigned_by by any accepted value. Filter by assigning organisation name Example: odit

filter[assignment_status]   string  optional    

Filter column assignment_status by any accepted value. Matches exact value. Example: UNDER_REVIEW

Must be one of:
  • UNDER_REVIEW
  • ACCEPTED
  • EXPIRED
  • DECLINED
filter[assigned_at]   datetime  optional    

Filter column assigned_at by any accepted value. Filter by assignment created date Example: <= 2026-08-26 14:29:40

search   string  optional    

Search in all of these columns: product_reference_id, product_name, formulator_reference_id, formulator_name. Filter type: like. Minimum length: 3. Example: ipsam

sort   string  optional    

sort by any accepted column: product_reference_id, product_name, formulator_reference_id, formulator_name, assigned_by, assigned_at, assignment_status. prefix a "-" before the column name to sort in descending order Example: product_reference_id

Body Parameters

per_page   integer  optional    

Must be at least 1. Must not be greater than 100. Example: 24

search   string  optional    

Must be at least 3 characters. Example: bhzpayhaccjosflqusjfaakrboyihwqnnnkhrqxryvhegdxriakrjz

filter   string  optional    
product_reference_id   string  optional    

Example: fugit

product_name   string  optional    

Example: facere

formulator_reference_id   string  optional    

Example: aut

formulator_name   string  optional    

Example: molestiae

assigned_by   string  optional    

Example: temporibus

assignment_status   string  optional    
assigned_at   string  optional    

Example: rerum

sort   string  optional    

Decline an assigned product

requires authentication

Marks the assignment identified in the URL as declined.

Example request:
curl --request PATCH \
    "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/assigned-products/1234567890/decline" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"note\": \"Unable to process at this time.\"
}"
const url = new URL(
    "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/assigned-products/1234567890/decline"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "note": "Unable to process at this time."
};

fetch(url, {
    method: "PATCH",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "data": {
        "product_reference_id": null,
        "product_name": null,
        "formulator_reference_id": null,
        "formulator_name": null,
        "assigned_by": null,
        "assigned_at": "2026-08-20",
        "assignment_status": null
    }
}
 

Example response (200):


Success.
 

Example response (401):


Token not found
 

Example response (403):


Authenticated Organisation is not one of types ZDHC MRSL Certification Bodies
 

Example response (403):


User does not have required permission.
 

Example response (404):


Resource not found.
 

Example response (422):


Validation error
 

Request      

PATCH api/certification-bodies/v1/assigned-products/{product_reference_id}/decline

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

product_reference_id   string     

The reference ID of the assigned product. Example: 1234567890

Body Parameters

note   string     

Decline note. Must not be greater than 255 characters. Example: Unable to process at this time.

Certificates

List certificates

requires authentication

Returns a paginated list of certificates for this certification body.

Example request:
curl --request GET \
    --get "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/certificates?per_page=13&page=1&filter%5Bproduct_reference_id%5D=quam&filter%5Bstandard_reference_id%5D=quos&filter%5Bstatus%5D=ACTIVE&sort=certificate_reference_id" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"per_page\": 10,
    \"filter\": {
        \"product_reference_id\": \"iure\",
        \"standard_reference_id\": \"veritatis\"
    }
}"
const url = new URL(
    "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/certificates"
);

const params = {
    "per_page": "13",
    "page": "1",
    "filter[product_reference_id]": "quam",
    "filter[standard_reference_id]": "quos",
    "filter[status]": "ACTIVE",
    "sort": "certificate_reference_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",
};

let body = {
    "per_page": 10,
    "filter": {
        "product_reference_id": "iure",
        "standard_reference_id": "veritatis"
    }
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "data": [
        {
            "certificate_reference_id": "50-NFDPWTZDQRMG-M",
            "product_reference_id": "20-PL7DRAXCLWMF-L",
            "product_name": "Alpha External Certificate Product",
            "standard_reference_id": "30-4C4GQQESZTS8-C",
            "standard_name": "ExternalCertStandardAlpha",
            "certificate_number": "CERT-ALPHA-001",
            "certificate_issue_date": "2024-01-10",
            "certificate_end_date": "2027-01-10",
            "certificate_result": "PASSED",
            "ctz_level": "foundational",
            "gateway_active_until": "2027-06-10",
            "sds_source": "formulator",
            "status": "ACTIVE",
            "removal_status": "pending",
            "created_at": "2024-01-10T00:00:00.000000Z"
        },
        {
            "certificate_reference_id": "50-V38K8BRA7RZR-P",
            "product_reference_id": "20-4N3JQKHUY8Q7-P",
            "product_name": "Alpha External Certificate Product",
            "standard_reference_id": "30-RDTVFZQNCDB7-K",
            "standard_name": "ExternalCertStandardAlpha",
            "certificate_number": "CERT-ALPHA-001",
            "certificate_issue_date": "2024-01-10",
            "certificate_end_date": "2027-01-10",
            "certificate_result": "PASSED",
            "ctz_level": "foundational",
            "gateway_active_until": "2027-06-10",
            "sds_source": "formulator",
            "status": "ACTIVE",
            "removal_status": "pending",
            "created_at": "2024-01-10T00:00:00.000000Z"
        }
    ],
    "links": {
        "first": "/?page=1",
        "last": "/?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "links": [
            {
                "url": null,
                "label": "&laquo; Previous",
                "active": false
            },
            {
                "url": "/?page=1",
                "label": "1",
                "active": true
            },
            {
                "url": null,
                "label": "Next &raquo;",
                "active": false
            }
        ],
        "path": "/",
        "per_page": 50,
        "to": 2,
        "total": 2
    }
}
 

Example response (200):


Success.
 

Example response (401):


Token not found
 

Example response (403):


Authenticated Organisation is not one of types ZDHC MRSL Certification Bodies
 

Example response (403):


User does not have required permission.
 

Example response (422):


Validation error
 

Request      

GET api/certification-bodies/v1/certificates

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

per_page   integer  optional    

Number of items to show per page. Defaults to 50 Example: 13

page   integer  optional    

the page number to show. Example: 1

filter[product_reference_id]   string  optional    

Filter column product_reference_id by any accepted value. Filter by product reference ID Example: quam

filter[standard_reference_id]   string  optional    

Filter column standard_reference_id by any accepted value. Filter by MRSL standard reference ID Example: quos

filter[status]   string  optional    

Filter column status by any accepted value. Matches exact value. Example: ACTIVE

Must be one of:
  • ACTIVE
  • INACTIVE
sort   string  optional    

sort by any accepted column: certificate_reference_id, product_reference_id, product_name, standard_reference_id, standard_name, certificate_number, certificate_issue_date, certificate_end_date, ctz_level, gateway_active_until, status, created_at. prefix a "-" before the column name to sort in descending order Example: certificate_reference_id

Body Parameters

per_page   integer  optional    

Must be at least 1. Must not be greater than 100. Example: 10

filter   object  optional    
product_reference_id   string  optional    

Example: iure

standard_reference_id   string  optional    

Example: veritatis

status   string  optional    
sort   string  optional    

Show a certificate

requires authentication

Returns one certificate for this certification body.

Example request:
curl --request GET \
    --get "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/certificates/50-AAAAAAAAAAA1-X" \
    --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/certificates/50-AAAAAAAAAAA1-X"
);

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": {
        "certificate_reference_id": "50-PLBRHK6KZL4U-D",
        "product_reference_id": "20-LGJSRMVVJ4VV-I",
        "product_name": "Alpha External Certificate Product",
        "standard_reference_id": "30-4PYHMD266MFW-Y",
        "standard_name": "ExternalCertStandardAlpha",
        "certificate_number": "CERT-ALPHA-001",
        "certificate_issue_date": "2024-01-10",
        "certificate_end_date": "2027-01-10",
        "certificate_result": "PASSED",
        "ctz_level": "foundational",
        "gateway_active_until": "2027-06-10",
        "sds_source": "formulator",
        "status": "ACTIVE",
        "removal_status": "pending",
        "created_at": "2024-01-10T00:00:00.000000Z"
    }
}
 

Example response (200):


Success.
 

Example response (401):


Token not found
 

Example response (403):


Authenticated Organisation is not one of types ZDHC MRSL Certification Bodies
 

Example response (403):


User does not have required permission.
 

Example response (404):


Resource not found.
 

Request      

GET api/certification-bodies/v1/certificates/{certificate_reference_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

certificate_reference_id   string     

Certificate reference ID. Example: 50-AAAAAAAAAAA1-X

Store a certificate

requires authentication

Stores a new certificate for this certification body.

Example request:
curl --request POST \
    "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/certificates" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"product_reference_id\": \"20-Z3X9V2N-1\",
    \"standard_reference_id\": \"10-A1B2C3D-4\",
    \"certificate_number\": \"1234567890\",
    \"certificate_issue_date\": \"2026-01-01\",
    \"certificate_end_date\": \"2026-01-01\",
    \"certificate_result\": \"Pass\",
    \"ctz_level\": \"foundational\",
    \"sds_source\": \"formulator\",
    \"sds_id\": 1
}"
const url = new URL(
    "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/certificates"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "product_reference_id": "20-Z3X9V2N-1",
    "standard_reference_id": "10-A1B2C3D-4",
    "certificate_number": "1234567890",
    "certificate_issue_date": "2026-01-01",
    "certificate_end_date": "2026-01-01",
    "certificate_result": "Pass",
    "ctz_level": "foundational",
    "sds_source": "formulator",
    "sds_id": 1
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "data": {
        "certificate_reference_id": "50-RMNK6N7ERZ7L-Q",
        "product_reference_id": "20-9SSMVNY3EF3S-N",
        "product_name": "Alpha External Certificate Product",
        "standard_reference_id": "30-HV9WKACXD2F2-R",
        "standard_name": "ExternalCertStandardAlpha",
        "certificate_number": "CERT-ALPHA-001",
        "certificate_issue_date": "2024-01-10",
        "certificate_end_date": "2027-01-10",
        "certificate_result": "PASSED",
        "ctz_level": "foundational",
        "gateway_active_until": "2027-06-10",
        "sds_source": "formulator",
        "status": "ACTIVE",
        "removal_status": "pending",
        "created_at": "2024-01-10T00:00:00.000000Z"
    }
}
 

Example response (201):


Certificate created successfully.
 

Example response (401):


Token not found
 

Example response (403):


Authenticated Organisation is not one of types ZDHC MRSL Certification Bodies
 

Example response (403):


User does not have required permission.
 

Example response (403):


You are not accredited for this standard.
 

Example response (403):


Your accreditation does not permit the requested CtZ level.
 

Example response (404):


Product not found.
 

Example response (404):


Safety data sheet not found.
 

Example response (404):


Selected safety data sheet not found.
 

Example response (404):


Standard not found.
 

Example response (422):


Validation error
 

Request      

POST api/certification-bodies/v1/certificates

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

product_reference_id   string     

Reference ID of the chemical product to certify. If the product is not yet assigned to the authenticated certification body, an assignment is created automatically. Must match the regex /^20-[2346789ABCDEFGHJKLMNPQRSTUVWXYZ]{8,}-[ABCDEFGHIJKLMNOPQRSTUVWXYZ]$/. Example: 20-Z3X9V2N-1

standard_reference_id   string     

Reference ID of the MRSL standard to certify against. The standard must exist and be accredited for the authenticated certification body. Must match the regex /^30-[2346789ABCDEFGHJKLMNPQRSTUVWXYZ]{8,}-[ABCDEFGHIJKLMNOPQRSTUVWXYZ]$/. Example: 10-A1B2C3D-4

certificate_number   string  optional    

Optional certificate number (string, max 255 characters). Omit or leave empty to store null. Must not be greater than 255 characters. Example: 1234567890

certificate_issue_date   string     

Certificate issue date (date). Must be a valid date in the format Y-m-d. Example: 2026-01-01

certificate_end_date   string  optional    

Optional certificate end date (date). Omit or leave empty to store null; gateway_active_until defaults to three years from now. Must be a valid date in the format Y-m-d. Example: 2026-01-01

certificate_result   string  optional    

Optional certificate result (string, max 255 characters). Omit or leave empty to store null. Must not be greater than 255 characters. Example: Pass

ctz_level   string     

CTZ level for the certificate. Accepted values: foundational, progressive, aspirational.

The value must be allowed for the selected MRSL standard's conformance level:

  • MRSL conformance level 1: foundational only
  • MRSL conformance level 2: foundational or progressive
  • MRSL conformance level 3: foundational, progressive, or aspirational. Example: foundational
sds_source   string     

Which safety data sheet (SDS) to base the certification on. Use formulator for the SDS uploaded by the chemical formulator, or certifier for an SDS uploaded by the authenticated certification body. Example: formulator

sds_id   integer  optional    

Safety data sheet ID of a previously uploaded safety data sheet. Required when the formulator has not uploaded a valid SDS for the product; optional when a formulator SDS exists and can be resolved from sds_source. Example: 1

Remove a certificate

requires authentication

Removes a certificate for this certification body.

Example request:
curl --request PATCH \
    "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/certificates/1/remove" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"reason\": \"QUALITY_ISSUE\",
    \"note\": \"Chemical product is no longer compliant with the certification body\'s requirements.\"
}"
const url = new URL(
    "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/certificates/1/remove"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "reason": "QUALITY_ISSUE",
    "note": "Chemical product is no longer compliant with the certification body's requirements."
};

fetch(url, {
    method: "PATCH",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "data": {
        "certificate_reference_id": "50-JD3WLBDGPKWZ-R",
        "product_reference_id": "20-MKFR382SBAFA-F",
        "product_name": "Alpha External Certificate Product",
        "standard_reference_id": "30-7U3U6TSKTDF2-K",
        "standard_name": "ExternalCertStandardAlpha",
        "certificate_number": "CERT-ALPHA-001",
        "certificate_issue_date": "2024-01-10",
        "certificate_end_date": "2027-01-10",
        "certificate_result": "PASSED",
        "ctz_level": "foundational",
        "gateway_active_until": "2027-06-10",
        "sds_source": "formulator",
        "status": "ACTIVE",
        "removal_status": "pending",
        "created_at": "2024-01-10T00:00:00.000000Z"
    }
}
 

Example response (200):


Certificate removed successfully.
 

Example response (401):


Token not found
 

Example response (403):


Authenticated Organisation is not one of types ZDHC MRSL Certification Bodies
 

Example response (403):


User does not have required permission.
 

Example response (404):


Resource not found.
 

Example response (409):


Certificate already removed.
 

Example response (422):


Validation error
 

Request      

PATCH api/certification-bodies/v1/certificates/{id}/remove

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

Certificate ID. Example: 1

Body Parameters

reason   string     

Certification removal reason category. Example: QUALITY_ISSUE

Must be one of:
  • QUALITY_ISSUE
  • SDS_CHANGE
  • ENTRY_ERROR
  • OTHER
note   string  optional    

Optional additional note for the removal. Must not be greater than 255 characters. Example: Chemical product is no longer compliant with the certification body's requirements.

Bulk store certificates

requires authentication

Creates multiple certificates in one request. Each row is validated and processed independently; row-level failures do not prevent other rows from being created.

Example request:
curl --request POST \
    "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/certificates/bulk" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"rows\": [
        {
            \"product_reference_id\": \"20-Z3X9V2N-1\",
            \"standard_reference_id\": \"10-A1B2C3D-4\",
            \"certificate_number\": \"1234567890\",
            \"certificate_result\": \"Pass\",
            \"certificate_issue_date\": \"2026-01-01\",
            \"certificate_end_date\": \"2026-01-01\",
            \"ctz_level\": \"foundational\",
            \"sds_source\": \"formulator\",
            \"sds_id\": 1
        }
    ]
}"
const url = new URL(
    "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/certificates/bulk"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "rows": [
        {
            "product_reference_id": "20-Z3X9V2N-1",
            "standard_reference_id": "10-A1B2C3D-4",
            "certificate_number": "1234567890",
            "certificate_result": "Pass",
            "certificate_issue_date": "2026-01-01",
            "certificate_end_date": "2026-01-01",
            "ctz_level": "foundational",
            "sds_source": "formulator",
            "sds_id": 1
        }
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (207, Batch processed. Each row reports success or error independently.):


{
    "message": "Batch processed. Check each result individually.",
    "data": {
        "results": [
            {
                "row": 1,
                "status": "success",
                "certificate_reference_id": "50-AAAAAAAAAAA1-X",
                "product_reference_id": "40-AAAAAAAAAAA1-X",
                "gateway_active_until": "2028-01-15",
                "ctz_level": "foundational"
            },
            {
                "row": 2,
                "status": "error",
                "errors": [
                    "Product not found."
                ]
            }
        ],
        "summary": {
            "total": 2,
            "succeeded": 1,
            "failed": 1
        }
    }
}
 

Example response (207):


Batch processed. Check each result individually.
 

Example response (401):


Token not found
 

Example response (403):


Authenticated Organisation is not one of types ZDHC MRSL Certification Bodies
 

Example response (403):


User does not have required permission.
 

Example response (422):


Validation error
 

Request      

POST api/certification-bodies/v1/certificates/bulk

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

rows   object[]     

Array of certificate rows to create. Each row uses the same fields as the single certificate store endpoint. Must have at least 1 items.

product_reference_id   string     

Reference ID of the chemical product to certify. If the product is not yet assigned to the authenticated certification body, an assignment is created automatically. Must match the regex /^20-[2346789ABCDEFGHJKLMNPQRSTUVWXYZ]{8,}-[ABCDEFGHIJKLMNOPQRSTUVWXYZ]$/. Example: 20-Z3X9V2N-1

standard_reference_id   string     

Reference ID of the MRSL standard to certify against. The standard must exist and be accredited for the authenticated certification body. Must match the regex /^30-[2346789ABCDEFGHJKLMNPQRSTUVWXYZ]{8,}-[ABCDEFGHIJKLMNOPQRSTUVWXYZ]$/. Example: 10-A1B2C3D-4

certificate_number   string  optional    

Optional certificate number (string, max 255 characters). Omit or leave empty to store null. Example: 1234567890

certificate_result   string  optional    

Optional certificate result (string, max 255 characters). Omit or leave empty to store null. Example: Pass

certificate_issue_date   string  optional    

Certificate issue date (date). Example: 2026-01-01

certificate_end_date   string  optional    

Optional certificate end date (date). Omit or leave empty to store null; gateway_active_until defaults to three years from now. Example: 2026-01-01

ctz_level   string     

CTZ level for the certificate. Accepted values: foundational, progressive, aspirational.

The value must be allowed for the selected MRSL standard's conformance level:

  • MRSL conformance level 1: foundational only
  • MRSL conformance level 2: foundational or progressive
  • MRSL conformance level 3: foundational, progressive, or aspirational. Example: foundational
sds_source   string     

Which safety data sheet (SDS) to base the certification on. Use formulator for the SDS uploaded by the chemical formulator, or certifier for an SDS uploaded by the authenticated certification body. Example: formulator

sds_id   integer  optional    

Safety data sheet ID of a previously uploaded safety data sheet. Required when the formulator has not uploaded a valid SDS for the product; optional when a formulator SDS exists and can be resolved from sds_source. Example: 1

Products

List chemical products

requires authentication

Returns a paginated list of chemical products.

Example request:
curl --request GET \
    --get "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/products?per_page=18&page=1&filter%5Bproduct_reference_id%5D=architecto&filter%5Bname%5D=nemo&filter%5Bzdhc_pid%5D=15&filter%5Bstatus%5D=PUBLISHED&filter%5Bformulator_reference_id%5D=non&filter%5Bformulator_name%5D=sed&filter%5Bconformance_level_id%5D=14&filter%5Bctz_level_id%5D=4&filter%5Bproduct_use_type_id%5D=6&filter%5Bproduct_category_id%5D=11&filter%5Bcreated_at%5D=%3E%3D+2026-08-25+14%3A29%3A40&filter%5Bupdated_at%5D=%3E%3D+2026-08-25+14%3A29%3A40&search=ut&sort=id" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"per_page\": 15,
    \"search\": \"bdcyvpbvqvthmcxozcslvxnwsxxsviwslvtafiijavbvgtnlcswanljkckuw\"
}"
const url = new URL(
    "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/products"
);

const params = {
    "per_page": "18",
    "page": "1",
    "filter[product_reference_id]": "architecto",
    "filter[name]": "nemo",
    "filter[zdhc_pid]": "15",
    "filter[status]": "PUBLISHED",
    "filter[formulator_reference_id]": "non",
    "filter[formulator_name]": "sed",
    "filter[conformance_level_id]": "14",
    "filter[ctz_level_id]": "4",
    "filter[product_use_type_id]": "6",
    "filter[product_category_id]": "11",
    "filter[created_at]": ">= 2026-08-25 14:29:40",
    "filter[updated_at]": ">= 2026-08-25 14:29:40",
    "search": "ut",
    "sort": "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",
};

let body = {
    "per_page": 15,
    "search": "bdcyvpbvqvthmcxozcslvxnwsxxsviwslvtafiijavbvgtnlcswanljkckuw"
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "data": [
        {
            "product_reference_id": "20-H7XK3DRZ9BDA-H",
            "name": "Alpha External Product",
            "formulator_reference_id": "01-L8RASYDMLMWQ-H",
            "formulator_name": "Chemical Formulator Alpha",
            "classifications": [
                {
                    "use_type_name": "Softening agents",
                    "category_name": "Textile Finishing Assistants",
                    "substrate_name": "Textile"
                }
            ],
            "sds_url": "https://example.com/sds.pdf"
        },
        {
            "product_reference_id": "20-P62Q8RWECPH2-R",
            "name": "Alpha External Product",
            "formulator_reference_id": "01-BVSPQ8GK2M8K-D",
            "formulator_name": "Chemical Formulator Alpha",
            "classifications": [
                {
                    "use_type_name": "Softening agents",
                    "category_name": "Textile Finishing Assistants",
                    "substrate_name": "Textile"
                }
            ],
            "sds_url": "https://example.com/sds.pdf"
        }
    ],
    "links": {
        "first": "/?page=1",
        "last": "/?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "links": [
            {
                "url": null,
                "label": "&laquo; Previous",
                "active": false
            },
            {
                "url": "/?page=1",
                "label": "1",
                "active": true
            },
            {
                "url": null,
                "label": "Next &raquo;",
                "active": false
            }
        ],
        "path": "/",
        "per_page": 50,
        "to": 2,
        "total": 2
    }
}
 

Example response (200):


Success.
 

Example response (401):


Token not found
 

Example response (403):


Authenticated Organisation is not one of types ZDHC MRSL Certification Bodies
 

Example response (403):


User does not have required permission.
 

Example response (422):


Validation error
 

Request      

GET api/certification-bodies/v1/products

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

per_page   integer  optional    

Number of items to show per page. Defaults to 50 Example: 18

page   integer  optional    

the page number to show. Example: 1

filter[product_reference_id]   string  optional    

Filter column product_reference_id by any accepted value. Filter by product reference ID Example: architecto

filter[name]   string  optional    

Filter column name by any accepted value. Filter by product name Example: nemo

filter[zdhc_pid]   integer  optional    

Filter column zdhc_pid by any accepted value. Filter by ZDHC PID Example: 15

filter[status]   string  optional    

Filter column status by any accepted value. Filter by publication status (maps to publication_status) Example: PUBLISHED

Must be one of:
  • PUBLISHED
  • UNPUBLISHED
filter[formulator_reference_id]   string  optional    

Filter column formulator_reference_id by any accepted value. Filter by formulator reference ID Example: non

filter[formulator_name]   string  optional    

Filter column formulator_name by any accepted value. Filter by formulator name Example: sed

filter[conformance_level_id]   integer  optional    

Filter column conformance_level_id by any accepted value. Filter by conformance level IDs Example: 14

filter[ctz_level_id]   integer  optional    

Filter column ctz_level_id by any accepted value. Filter by CTZ level IDs Example: 4

filter[product_use_type_id]   integer  optional    

Filter column product_use_type_id by any accepted value. Filter by use type ID (multiple selection allowed) Example: 6

filter[product_category_id]   integer  optional    

Filter column product_category_id by any accepted value. Filter by product category ID (multiple selection allowed) Example: 11

filter[created_at]   datetime  optional    

Filter column created_at by any accepted value. Filter by created date Example: >= 2026-08-25 14:29:40

filter[updated_at]   datetime  optional    

Filter column updated_at by any accepted value. Filter by updated date Example: >= 2026-08-25 14:29:40

search   string  optional    

Search in all of these columns: product_reference_id, name, alternate_names, zdhc_pid, formulator_reference_id, formulator_name. Filter type: like. Minimum length: 3. Example: ut

sort   string  optional    

sort by any accepted column: id, product_reference_id, name, version, status, zdhc_pid, conformance_level_name, ctz_level_name, formulator_reference_id, formulator_name, created_at, updated_at. prefix a "-" before the column name to sort in descending order Example: id

Body Parameters

per_page   integer  optional    

Must be at least 1. Must not be greater than 100. Example: 15

search   string  optional    

Must be at least 3 characters. Example: bdcyvpbvqvthmcxozcslvxnwsxxsviwslvtafiijavbvgtnlcswanljkckuw

filter   string  optional    
product_reference_id   string  optional    

Example: repellendus

name   string  optional    

Example: aut

zdhc_pid   integer  optional    

Example: 6

status   string  optional    
formulator_reference_id   string  optional    

Example: quis

formulator_name   string  optional    

Example: nam

conformance_level_id   string  optional    

Example: a

ctz_level_id   string  optional    

Example: enim

product_use_type_id   string  optional    

Example: ut

product_category_id   string  optional    

Example: cumque

created_at   string  optional    

Example: ad

updated_at   string  optional    

Example: ut

sort   string  optional    

Show a chemical product

requires authentication

Returns one chemical product.

Example request:
curl --request GET \
    --get "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/products/20-Z3X9V2N-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/products/20-Z3X9V2N-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": {
        "product_reference_id": "20-S97499D8VUWN-U",
        "name": "Alpha External Product",
        "formulator_reference_id": "01-EJ2DVKJQGVQM-S",
        "formulator_name": "Chemical Formulator Alpha",
        "classifications": [
            {
                "use_type_name": "Softening agents",
                "category_name": "Textile Finishing Assistants",
                "substrate_name": "Textile"
            }
        ],
        "sds_url": "https://example.com/sds.pdf"
    }
}
 

Example response (200):


Success.
 

Example response (401):


Token not found
 

Example response (403):


Authenticated Organisation is not one of types ZDHC MRSL Certification Bodies
 

Example response (403):


User does not have required permission.
 

Example response (404):


Resource not found.
 

Request      

GET api/certification-bodies/v1/products/{product_reference_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

product_reference_id   string     

Reference ID of the chemical product. Example: 20-Z3X9V2N-1

Safety Data Sheets

Upload a safety data sheet

requires authentication

Uploads a safety data sheet PDF for a chemical product on behalf of the authenticated certification body.

Example request:
curl --request POST \
    "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/sds" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: multipart/form-data" \
    --header "Accept: application/json" \
    --form "product_reference_id=20-T3TDADC386W6-D"\
    --form "file=@/tmp/phpdjfGHM" 
const url = new URL(
    "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/sds"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "multipart/form-data",
    "Accept": "application/json",
};

const body = new FormData();
body.append('product_reference_id', '20-T3TDADC386W6-D');
body.append('file', document.querySelector('input[name="file"]').files[0]);

fetch(url, {
    method: "POST",
    headers,
    body,
}).then(response => response.json());

Example response (200):


{
    "data": {
        "sds_id": 1042,
        "product_reference_id": "20-F6BDHX334K7U-R",
        "sds_url": "https://cdn.example.com/sds/cb-1042.pdf",
        "uploaded_at": "2026-06-10T09:00:00.000000Z"
    }
}
 

Example response (201):


Safety data sheet uploaded successfully.
 

Example response (401):


Token not found
 

Example response (403):


Authenticated Organisation is not one of types ZDHC MRSL Certification Bodies
 

Example response (403):


User does not have required permission.
 

Example response (404):


Product not found.
 

Example response (422):


Validation error
 

Request      

POST api/certification-bodies/v1/sds

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: multipart/form-data

Accept        

Example: application/json

Body Parameters

product_reference_id   string     

Reference ID of the chemical product. Must match the regex /^20-[2346789ABCDEFGHJKLMNPQRSTUVWXYZ]{8,}-[ABCDEFGHIJKLMNOPQRSTUVWXYZ]$/. Example: 20-T3TDADC386W6-D

file   file     

Safety data sheet PDF file. Must be a file. Must not be greater than 10240 kilobytes. Example: /tmp/phpdjfGHM

Download a safety data sheet

requires authentication

Downloads a safety data sheet for a chemical product.

Example request:
curl --request GET \
    --get "https://staging-api.vm400.consulting1x1.info/api/certification-bodies/v1/sds/1042" \
    --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/sds/1042"
);

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
 

Example response (401):


Token not found
 

Example response (403):


Authenticated Organisation is not one of types ZDHC MRSL Certification Bodies
 

Example response (403):


User does not have required permission.
 

Example response (404):


Resource not found.
 

Request      

GET api/certification-bodies/v1/sds/{id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

Safety data sheet ID. Example: 1042