Skip to main content

Private Portal API - Quality Docs (v0)

Download OpenAPI specification:Download

The Quality Docs section of the Private Portal API gives the owner of a Kemiex private portal programmatic, read-only access to the quality documentation its suppliers maintain in the portal: which documents are required, which ones were uploaded, when they expire, what your quality team decided about them, and the files themselves. It lets you mirror the Quality Docs overview of the portal into your ERP, vendor-qualification or document-management system, instead of exporting it by hand.

Suppliers keep uploading through the portal; nothing is written through this API.

Access

Requests are authenticated with the Api-Key header. The key is the one of a user of the portal owner, generated under User settings, API tab, and carries that user's company. The ERP integration must be enabled for your company by your Kemiex account manager, and your private portal must have Quality Docs enabled; otherwise every call is refused with 403 FORBIDDEN.

Every call is scoped to your portal: the suppliers, documents, templates and files you see are the ones of the private portal your company owns, and a resource of another portal behaves as if it did not exist (404).

The data model

  • A supplier is a company of your private portal. Each supplier carries two kinds of quality documentation:
    • Supplier documents describe the supplier itself (quality certificates, audits, evaluation forms).
    • Product/manufacturer combinations describe each product you buy from the supplier, per manufacturer of that product. Each combination holds its own product documents (CoA, MSDS, TDS, GMP certificates...), your internal product id for that combination, and the note or warning your quality team attached to it.
  • A template is a document type your portal requires from every supplier, or from every product/manufacturer combination, configured by Kemiex on your behalf. A document that fulfils a template is marked required: true and references the template; a template no supplier document fulfils yet is reported as a document with validity: MISSING, so the gaps are visible without a second call. Suppliers may also upload documents nobody asked for; those come with required: false.
  • Buyer entities are the companies of your group (for instance one legal entity per market or sector). Approval decisions are taken per buyer entity, so every supplier, product/manufacturer combination and document carries one approval entry per entity of your group.

The examples in this document follow one such group: a feed entity and a food entity that share suppliers, each requesting its own document types, so the same document can be approved by one entity and rejected or not applicable for the other.

Status reference

Approval status (per buyer entity, on suppliers, product/manufacturer combinations and documents):

Status Meaning
PENDING Nobody of that entity has decided yet. Default for an entity that requires the item
APPROVED Approved by a quality responsible of that entity
REJECTED Rejected by a quality responsible of that entity; reason usually says why
NOT_APPLICABLE The item is not required by that entity, or was explicitly marked as not applicable (typically with a reason such as "Feed only")
APPROVED_BY_OTHERS Derived: the entity took no decision, but every other entity requiring the item approved it

Validity (per document, independent of approvals):

Validity Meaning
VALID A file was uploaded and the document has not expired (no expiration date, or a date in the future)
EXPIRED A file was uploaded but the expiration date is in the past (compared against the current UTC date)
MISSING The document is required by one of your templates and no file was uploaded for it yet

Synchronisation patterns

Both of these are supported; pick the one that fits your integration:

  • Full pull. List the suppliers (GET /pp/v1/quality-docs/suppliers), then fetch each one in full (GET /pp/v1/quality-docs/suppliers/{supplierUuid}): all its documents, grouped the way the portal shows them.
  • Incremental. Poll GET /pp/v1/quality-docs/documents?lastUpdateFrom=... with the timestamp of your previous run. It returns every document whose file, details, expiration date or approval changed since then, newly required documents included, each one labelled with its supplier and product/manufacturer combination, so one request keeps your copy current. Use the same filter on the supplier list to find the suppliers that changed.

Pagination is page-based: page starts at 1 and pageSize should stay constant while walking the pages of one query.

Identifiers

  • Every Kemiex entity (supplier, buyer entity, product/manufacturer combination, document, template, document type, product, manufacturer, file) is addressed by a uuid. It is the only identifier to store on your side: it stays the same through data maintenance on our side, and it is what every path parameter and filter of this API accepts. Numbers shown in the portal's interface are not part of the contract.
  • supplierCode and internalProductId are your own codes, maintained in the portal by your team, returned as stored so you can match suppliers and product/manufacturer combinations in your ERP. Both are optional and null when not set.
  • A file's uuid identifies the current version of that file; a new upload on the same document gets a new one.

Dates and times

Expiration dates are calendar dates (YYYY-MM-DD), without a time. Every timestamp is in UTC, ISO 8601 (2025-02-27T07:48:46Z). Timestamp filters accept an offset too (2025-02-27T08:48:46+01:00); when the + of an offset reaches the server as a space it is put back, but encoding it as %2B is safer.

Trace headers

In addition to the standard headers that you would expect, each response contains 2 specific headers. When asking for support, please provide them as reference if possible:

Header Description
X-Trace-Id Trace identifier used to track each request against internal logs
X-Server-Version Version of the server that responded

Errors

Kemiex uses conventional HTTP response codes to indicate the success or failure of an API request. In general: codes in the 2xx range indicate success. Codes in the 4xx range indicate an error that failed given the information provided. Codes in the 5xx range indicate an error with Kemiex's servers.

Unsuccessful responses contain 2 parts: an error code, and a user-friendly message describing the issue. You can expect the following errors, though more may be added in the future:

Error Code Description
BAD_REQUEST_RESOURCE_NOT_FOUND Client-side error: the URL address is wrong
BAD_REQUEST_METHOD_NOT_SUPPORTED Client-side error: the HTTP method used in the request is not supported by the endpoint
BAD_REQUEST_MISSING_REQUIRED_PARAMETER Client-side error: at least one of the required parameters is not provided
BAD_REQUEST_PARAMETER_TYPE_MISMATCH Client-side error: a parameter value does not match its expected type
BAD_REQUEST_PARAMETER_VALUE_ILLEGAL Client-side error: a parameter value is outside the range of values allowed
BAD_REQUEST General client-side error: the request cannot be processed. This is a catch-all error thrown when the errors above do not apply
FORBIDDEN The API key is not provided, or the provided value is incorrect, or the associated account does not have access to the requested resource
INTERNAL_SERVER_ERROR An unexpected condition was encountered on the server

Rate limits

A rate limit of 100 requests per minute per API key is planned. Exceeding it returns HTTP code 429 with no body; wait for the next minute before retrying. Download URLs returned by the files endpoint are fetched from storage directly and do not count.

Suppliers

The suppliers of your private portal and their quality documentation, grouped as the portal shows it

List suppliers

Returns the suppliers of your portal with a summary of their quality documentation, ordered by name ascending. Each row carries the approval status of the supplier per buyer entity, document counts and the earliest expiration date; use GET /pp/v1/quality-docs/suppliers/{supplierUuid} for the documents themselves.

Without filters every supplier of the portal is returned, including inactive ones and those without any document.

Authorizations:
apiKey
query Parameters
name
string
Example: name=qingyuan

Only return suppliers whose name contains the given text, case insensitive.

supplierCode
string
Example: supplierCode=006512

Only return the supplier carrying this code of yours, matched exactly.

active
boolean
Example: active=true

Only return active (true) or inactive (false) suppliers. Omitted, both are returned.

hasDocuments
boolean
Example: hasDocuments=true

Only return suppliers with at least one uploaded document (true), or without any (false).

approvalStatus
string (ApprovalStatus)
Enum: "PENDING" "APPROVED" "REJECTED" "NOT_APPLICABLE" "APPROVED_BY_OTHERS"
Example: approvalStatus=APPROVED

Only return suppliers whose supplier-level approval has this status for at least one buyer entity, or for the entity given in buyerCompanyUuid.

buyerCompanyUuid
string <uuid>
Example: buyerCompanyUuid=6f5e4d3c-2b1a-4f9e-8d7c-6b5a4f3e2d1c

Evaluate approvalStatus against this buyer entity of your group only, instead of against any of them. Ignored without approvalStatus.

lastUpdateFrom
string <date-time>
Examples:
  • lastUpdateFrom=2026-10-19T20:15:30Z - Timestamp in Zulu timezone
  • lastUpdateFrom=2026-10-19T21:15:30+01:00 - Timestamp in UTC+1 timezone; encode the plus sign as `%2B`

Only return items updated after the given date/time (ISO 8601 format). Omitted, there is no lower bound.

lastUpdateTo
string <date-time>
Examples:
  • lastUpdateTo=2026-10-20T20:15:30Z - Timestamp in Zulu timezone
  • lastUpdateTo=2026-10-20T21:15:30+01:00 - Timestamp in UTC+1 timezone; encode the plus sign as `%2B`

Only return items updated before the given date/time (ISO 8601 format). If omitted, the current date/time is implied.

page
integer <int32> >= 1
Default: 1
Example: page=1

Desired page number of results. First page is 1.

pageSize
integer <int32> [ 1 .. 500 ]
Default: 100
Example: pageSize=50

Maximum number of results that should be returned per page. Please keep it constant for requests across multiple pages, in order to correctly receive all results.

Responses

Response samples

Content type
application/json
{
  • "results": [
    • {
      },
    • {
      }
    ],
  • "pageNumber": 1,
  • "pageSize": 2,
  • "totalResults": 348,
  • "totalPages": 174
}

Retrieve a supplier

Returns the complete quality documentation of one supplier, grouped the way the portal shows it: the supplier documents first, then the product/manufacturer combinations bought from the supplier, each with its documents.

Required document types nobody uploaded yet are included as documents with validity: MISSING, so the response is the full picture of what is expected from the supplier, not only of what was received.

Authorizations:
apiKey
path Parameters
supplierUuid
required
string <uuid>
Example: 2c7f3d9a-5e14-4b8c-9a61-0d3e7f2b8c45

The universal unique identifier of the supplier, as returned by the supplier list.

Responses

Response samples

Content type
application/json
{
  • "uuid": "2c7f3d9a-5e14-4b8c-9a61-0d3e7f2b8c45",
  • "name": "Hubei Qingyuan Biotech Co., Ltd.",
  • "supplierCode": "006512",
  • "active": true,
  • "approvals": [
    • {
      },
    • {
      }
    ],
  • "documentSummary": {
    • "uploaded": 11,
    • "missing": 3,
    • "expired": 1,
    • "earliestExpirationDate": "2026-06-30"
    },
  • "lastUpdated": "2026-10-19T09:02:15Z",
  • "supplierDocuments": [
    • {
      },
    • {
      },
    • {
      },
    • {
      },
    • {
      },
    • {
      }
    ],
  • "productManufacturers": [
    • {
      },
    • {
      }
    ]
}

Documents

Every quality document across your suppliers, as one flat list built for incremental synchronisation

List documents

Returns the quality documents of every supplier of your portal as one flat list, each labelled with the supplier and, for product documents, the product/manufacturer combination it belongs to. The most recently updated documents come first.

This is the endpoint to poll for an incremental synchronisation: lastUpdateFrom returns the documents whose file, details, expiration date or approval changed since your previous run, and the documents that became required in the meantime, which arrive as MISSING entries dated when the requirement appeared.

Authorizations:
apiKey
query Parameters
lastUpdateFrom
string <date-time>
Examples:
  • lastUpdateFrom=2026-10-19T20:15:30Z - Timestamp in Zulu timezone
  • lastUpdateFrom=2026-10-19T21:15:30+01:00 - Timestamp in UTC+1 timezone; encode the plus sign as `%2B`

Only return items updated after the given date/time (ISO 8601 format). Omitted, there is no lower bound.

lastUpdateTo
string <date-time>
Examples:
  • lastUpdateTo=2026-10-20T20:15:30Z - Timestamp in Zulu timezone
  • lastUpdateTo=2026-10-20T21:15:30+01:00 - Timestamp in UTC+1 timezone; encode the plus sign as `%2B`

Only return items updated before the given date/time (ISO 8601 format). If omitted, the current date/time is implied.

supplierUuid
string <uuid>
Example: supplierUuid=2c7f3d9a-5e14-4b8c-9a61-0d3e7f2b8c45

Only return the documents of this supplier.

supplierCode
string
Example: supplierCode=006512

Only return the documents of the supplier carrying this code of yours, matched exactly.

category
string (DocumentCategory)
Enum: "SUPPLIER" "PRODUCT"
Example: category=PRODUCT

Only return supplier documents or product documents.

documentTypeUuid
Array of strings <uuid> [ items <uuid > ]
Example: documentTypeUuid=0c5b2f7d-4a6e-4b8c-9d1f-7e9a1b3c5d6f&documentTypeUuid=1d6c3a8e-5b7f-4c9d-8e2a-8f0b2c4d6e7a

Only return documents of this document type, as listed by the templates endpoint. Repeat the parameter for several types.

validity
string (Validity)
Enum: "VALID" "EXPIRED" "MISSING"
Example: validity=EXPIRED

Only return documents with this validity.

approvalStatus
string (ApprovalStatus)
Enum: "PENDING" "APPROVED" "REJECTED" "NOT_APPLICABLE" "APPROVED_BY_OTHERS"
Example: approvalStatus=PENDING

Only return documents whose approval has this status for at least one buyer entity, or for the entity given in buyerCompanyUuid.

buyerCompanyUuid
string <uuid>
Example: buyerCompanyUuid=6f5e4d3c-2b1a-4f9e-8d7c-6b5a4f3e2d1c

Evaluate approvalStatus against this buyer entity of your group only, instead of against any of them. Ignored without approvalStatus.

expirationFrom
string <date>
Example: expirationFrom=2026-01-01

Only return documents expiring on or after this date. Combined with expirationTo, a convenient way to list what expires in a given window.

expirationTo
string <date>
Example: expirationTo=2026-03-31

Only return documents expiring on or before this date.

page
integer <int32> >= 1
Default: 1
Example: page=1

Desired page number of results. First page is 1.

pageSize
integer <int32> [ 1 .. 500 ]
Default: 100
Example: pageSize=50

Maximum number of results that should be returned per page. Please keep it constant for requests across multiple pages, in order to correctly receive all results.

Responses

Response samples

Content type
application/json
{
  • "results": [
    • {
      },
    • {
      }
    ],
  • "pageNumber": 1,
  • "pageSize": 2,
  • "totalResults": 1958,
  • "totalPages": 979
}

Templates

The document types your portal requires from suppliers and from product/manufacturer combinations

List templates

Returns the document types your portal requires from suppliers (SUPPLIER templates) and from each product/manufacturer combination (PRODUCT templates), ordered by category and then by document type name. Use it to map Kemiex document types to the codes of your own system, and to know which templateUuid a missing document refers to.

When your portal requests documents per buyer entity, requiredBy names the entities asking for the template; otherwise it is empty and the template applies to every supplier of the portal. The same document type may appear several times with different details, for instance one evaluation form per entity or one packaging picture per pack format. A template may come with a form the supplier has to fill in, downloadable through the files endpoint.

Authorizations:
apiKey
query Parameters
category
string (DocumentCategory)
Enum: "SUPPLIER" "PRODUCT"
Example: category=SUPPLIER

Only return the templates of this category.

Responses

Response samples

Content type
application/json
[
  • {
    • "uuid": "b7e2a9c4-3d1f-4a6b-8e5c-9f0a1b2c3d31",
    • "category": "SUPPLIER",
    • "documentType": {
      },
    • "details": null,
    • "requiredBy": [
      ],
    • "form": null
    },
  • {
    • "uuid": "c8f3b0d5-4e2a-4b7c-9f6d-0a1b2c3d4e32",
    • "category": "SUPPLIER",
    • "documentType": {
      },
    • "details": null,
    • "requiredBy": [
      ],
    • "form": null
    },
  • {
    • "uuid": "d9a4c1e6-5f3b-4c8d-8a7e-1b2c3d4e5f33",
    • "category": "SUPPLIER",
    • "documentType": {
      },
    • "details": null,
    • "requiredBy": [
      ],
    • "form": null
    },
  • {
    • "uuid": "e0b5d2f7-6a4c-4d9e-9b8f-2c3d4e5f6a34",
    • "category": "SUPPLIER",
    • "documentType": {
      },
    • "details": "Feed",
    • "requiredBy": [
      ],
    • "form": {
      }
    },
  • {
    • "uuid": "f1c6e3a8-7b5d-4e0f-8c9a-3d4e5f6a7b35",
    • "category": "SUPPLIER",
    • "documentType": {
      },
    • "details": "Food",
    • "requiredBy": [
      ],
    • "form": {
      }
    },
  • {
    • "uuid": "a2d7f4b9-8c6e-4f1a-9d0b-4e5f6a7b8c36",
    • "category": "SUPPLIER",
    • "documentType": {
      },
    • "details": "Please sign the Code of Conduct and upload it to the platform.",
    • "requiredBy": [
      ],
    • "form": {
      }
    },
  • {
    • "uuid": "b3e8a5c0-9d7f-4a2b-8e1c-5f6a7b8c9d41",
    • "category": "PRODUCT",
    • "documentType": {
      },
    • "details": null,
    • "requiredBy": [
      ],
    • "form": null
    },
  • {
    • "uuid": "c4f9b6d1-0e8a-4b3c-9f2d-6a7b8c9d0e42",
    • "category": "PRODUCT",
    • "documentType": {
      },
    • "details": null,
    • "requiredBy": [
      ],
    • "form": null
    },
  • {
    • "uuid": "d5a0c7e2-1f9b-4c4d-8a3e-7b8c9d0e1f43",
    • "category": "PRODUCT",
    • "documentType": {
      },
    • "details": null,
    • "requiredBy": [
      ],
    • "form": null
    },
  • {
    • "uuid": "e6b1d8f3-2a0c-4d5e-9b4f-8c9d0e1f2a44",
    • "category": "PRODUCT",
    • "documentType": {
      },
    • "details": null,
    • "requiredBy": [
      ],
    • "form": null
    },
  • {
    • "uuid": "f7c2e9a4-3b1d-4e6f-8c5a-9d0e1f2a3b45",
    • "category": "PRODUCT",
    • "documentType": {
      },
    • "details": "Full pallet",
    • "requiredBy": [
      ],
    • "form": null
    },
  • {
    • "uuid": "a8d3f0b5-4c2e-4f7a-9d6b-0e1f2a3b4c46",
    • "category": "PRODUCT",
    • "documentType": {
      },
    • "details": "Bag",
    • "requiredBy": [
      ],
    • "form": null
    },
  • {
    • "uuid": "b9e4a1c6-5d3f-4a8b-8e7c-1f2a3b4c5d47",
    • "category": "PRODUCT",
    • "documentType": {
      },
    • "details": null,
    • "requiredBy": [
      ],
    • "form": {
      }
    }
]

Files

File-related operations

Retrieve a File

Returns the download URL of a file. For Quality Docs this covers the current file of any quality document of your suppliers and the forms attached to your templates, addressed by the uuid those endpoints return. The URL is valid for 10 minutes; fetch the content with a plain GET on it, without the Api-Key header.

Authorizations:
apiKey
path Parameters
fileUuid
required
string <uuid>
Example: 9b1e7c42-0d3a-4f7e-9c1b-2a6f0d7e5b11

The universal unique identifier of the file

Responses

Response samples