Appearance
Technical Check
A technical check assesses whether a manuscript meets a journal's structural and technical requirements and returns a compliance report. This page is the integration contract for the technical check: the event ChronosHub publishes when a manuscript is ready, and the events the partner publishes back as the check progresses.
Like the language check, this is asynchronous: messages flow over the ChronosHub Integration Framework in both directions, and a single check produces one outbound event and one or more inbound ones. All messages are JSON. The schemas below are JSON Schema (draft 2020-12).
Provisional. The inbound schemas below are derived from the partner's sample payloads. They will be replaced by the partner's formal schema once it is published. The outbound payload is the agreed v1, including its
dataobject.
This contract describes the check payloads only — not the transport-level concerns (topic provisioning, authentication) which are agreed per partner during onboarding.
Envelope
Every message is wrapped in an Integration Framework envelope. payload is a JSON-encoded string, not a nested object — the payload schemas in the rest of this page describe the document inside that string.
Outbound (ChronosHub → Integration Framework → partner):
json
{
"eventId": "6a1f0d2c-3b4e-5f60-8a7b-9c0d1e2f3a4b",
"eventType": "manuscript.uploaded",
"partnerName": "ExamplePartner",
"payload": "{\"correlationId\":\"technicalcheck:01J...\",\"fileUrl\":\"https://...\",\"data\":{...}}"
}Inbound (partner → Integration Framework → ChronosHub):
json
{
"eventId": "3f1d1f1e-9a4b-4c2f-8a1e-6d5c4b3a2f10",
"partnerId": "b1e2d3c4-5a6b-7c8d-9e0f-1a2b3c4d5e6f",
"eventType": "technical.report.status.updated",
"eventContractVersion": 1,
"payload": "{\"correlationId\":\"technicalcheck:01J...\",\"status\":\"PROCESSING\", ...}",
"receivedAt": "2026-08-18T02:45:09.627Z"
}correlationId inside every payload is the ChronosHub technical check id. It is the only thing tying the exchange together and must be echoed back unchanged on every inbound event.
Outbound: manuscript.uploaded
Published when a manuscript has been uploaded and is ready to check.
json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "ManuscriptUploadedPayload",
"type": "object",
"additionalProperties": false,
"required": ["correlationId", "fileUrl", "data"],
"properties": {
"correlationId": {
"type": "string",
"description": "ChronosHub technical check id. Echo this back on every inbound event.",
"minLength": 1
},
"fileUrl": {
"type": "string",
"format": "uri",
"description": "Time-limited, read-only download link for the manuscript. Accepted formats are .doc, .docx, .pdf and .tex."
},
"data": {
"type": "object",
"required": ["publisher", "journal", "manuscript"],
"properties": {
"publisher": {
"type": "object",
"required": ["publisherId"],
"properties": {
"publisherId": {
"type": "string",
"description": "ChronosHub customer code, lower case (for example acs).",
"minLength": 1
},
"publisherName": {
"type": "string",
"description": "Optional. The publisher's display name."
}
}
},
"journal": {
"type": "object",
"required": ["journalId"],
"properties": {
"journalId": {
"type": "string",
"description": "ChronosHub journal id.",
"minLength": 1
},
"journalName": {
"type": "string",
"description": "Optional. The journal title."
},
"issn": {
"type": "string",
"description": "Optional. Print ISSN."
},
"eissn": {
"type": "string",
"description": "Optional. Electronic ISSN."
}
}
},
"manuscript": {
"type": "object",
"required": ["stage"],
"properties": {
"manuscriptType": {
"type": "string",
"description": "Optional. The manuscript type as the submitting system names it, for example Original Article."
},
"stage": {
"type": "string",
"description": "Submission stage. NEW for a first submission. More values may follow, so accept a value you do not know."
}
}
}
}
}
}
}Example
json
{
"correlationId": "technicalcheck:01981f2a-7c4e-7b9d-9a3f-2c1e5d6b7a80",
"fileUrl": "https://stchronosmcprod.blob.core.windows.net/manuscripts/0198f2a7-....docx?sv=...",
"data": {
"publisher": { "publisherId": "acs", "publisherName": "American Chemical Society" },
"journal": {
"journalId": "0001-4842",
"journalName": "Accounts of Chemical Research",
"issn": "0001-4842",
"eissn": "1520-4898"
},
"manuscript": { "manuscriptType": "Original Article", "stage": "NEW" }
}
}An optional property with no value is left out, never sent as null. For example, a journal with no print ISSN, or a journal with no title, has no issn or journalName key. Partners must not assume any optional property is present. ChronosHub may add fields inside data later; partners must ignore fields they don't know.
eventId is a deterministic UUIDv5 derived from the correlation id, so an at-least-once redelivery carries the same eventId. Partners should de-duplicate on it rather than starting a second check.
Inbound: technical.report.status.updated
Progress signals while the check is running. Sent zero or more times.
json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "TechnicalReportStatusPayload",
"type": "object",
"required": ["correlationId", "status"],
"properties": {
"correlationId": { "type": "string", "minLength": 1 },
"status": {
"type": "string",
"description": "Progress state. A successful outcome is not reported here — it arrives as technical.report.generated.",
"enum": ["RECEIVED", "PROCESSING", "FAILED"]
},
"message": {
"type": ["string", "null"],
"description": "Human-readable detail, typically the reason on FAILED."
},
"reportId": {
"type": ["string", "null"],
"description": "Present once the report has been generated; absent on RECEIVED."
},
"processStartTime": {
"type": ["string", "null"],
"format": "date-time",
"description": "Null until processing begins."
},
"processEndTime": {
"type": ["string", "null"],
"format": "date-time",
"description": "Null unless the check has finished. On FAILED, null when the failure happens before processing starts."
}
}
}Example
json
{
"status": "RECEIVED",
"message": null,
"correlationId": "technicalcheck:01981f2a-7c4e-7b9d-9a3f-2c1e5d6b7a80",
"processEndTime": null,
"processStartTime": null
}Inbound: technical.report.generated
The terminal success event, carrying the finished report. The top level is camelCase; everything inside data is snake_case.
json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "TechnicalReportGeneratedPayload",
"type": "object",
"required": ["correlationId", "reportId", "data"],
"properties": {
"correlationId": { "type": "string", "minLength": 1 },
"reportId": {
"type": "string",
"description": "Partner identifier for the report. Always present here; status updates carry it once it exists."
},
"status": {
"type": "string",
"description": "Always SUCCESS in the samples. Allowed and ignored by ChronosHub; the event type already conveys the outcome."
},
"processStartTime": { "type": ["string", "null"], "format": "date-time" },
"processEndTime": { "type": ["string", "null"], "format": "date-time" },
"data": {
"type": "object",
"required": ["metadata", "summary", "compliance_results"],
"properties": {
"metadata": {
"type": "object",
"required": ["report_link"],
"description": "Report metadata. ChronosHub keeps only report_link.",
"properties": {
"report_link": {
"type": "string",
"format": "uri",
"description": "Link to the hosted report."
}
}
},
"summary": {
"type": "object",
"required": [
"overall_alert_rate", "total_checks", "pass_count", "alert_count", "unverifiable_count"
],
"properties": {
"overall_alert_rate": {
"type": "number",
"description": "Overall alert rate across the checks."
},
"total_checks": { "type": "integer" },
"pass_count": { "type": "integer" },
"alert_count": { "type": "integer" },
"unverifiable_count": { "type": "integer" }
}
},
"compliance_results": {
"type": "array",
"items": { "$ref": "#/$defs/complianceResult" }
}
}
}
},
"$defs": {
"complianceResult": {
"type": "object",
"required": ["check_id", "category", "severity", "title"],
"properties": {
"check_id": { "type": "string" },
"check_description": { "type": "string" },
"category": { "type": "string" },
"sub_category": { "type": "string" },
"severity": {
"type": "string",
"description": "Seen so far (lowercase): pass, alert, unverifiable. Left open until the formal schema fixes the values; ChronosHub stores it verbatim."
},
"title": { "type": "string" },
"feedback_message": {
"type": "string",
"description": "Guidance for the author. May be absent."
}
}
}
}
}Example
json
{
"data": {
"metadata": {
"report_id": "85c0fab3-0d7e-4c55-9d0f-6a1c2b3e4f50",
"report_link": "https://reports.example.com/technical/xxxx",
"manuscript_id": "MSID12345",
"file_name": "Sample_1.docx",
"journal_name": "Journal B",
"manuscript_type": "Original Article",
"stage_name": "New",
"created_at": "2026-08-18T02:45:09.627Z"
},
"summary": {
"overall_alert_rate": 0.14,
"total_checks": 36,
"pass_count": 31,
"alert_count": 5,
"unverifiable_count": 0
},
"compliance_results": [
{
"check_id": "COM008",
"check_description": "Checks whether the corresponding author is marked with an asterisk.",
"category": "Front Matter",
"sub_category": "Author Group",
"severity": "alert",
"title": "The corresponding author's name is not marked with an asterisk",
"feedback_message": "Asterisk next to corresponding author name not visible in author list on title page."
},
{
"check_id": "COM021",
"check_description": "Checks the keyword count.",
"category": "Additional Information",
"sub_category": "Count",
"severity": "unverifiable",
"title": "Unable to verify the keywords count"
}
]
},
"status": "SUCCESS",
"reportId": "01f06125-e060-4b02-9170-1bbba05879c2",
"correlationId": "technicalcheck:01981f2a-7c4e-7b9d-9a3f-2c1e5d6b7a80",
"processEndTime": "2026-09-08T15:44:36.943Z",
"processStartTime": "2026-09-08T15:44:13.219Z"
}Notes
- All property names are case-sensitive.
- A successful outcome never arrives as a status update.
statuscarries onlyRECEIVED,PROCESSINGandFAILED; success istechnical.report.generated. An unrecognised status value is rejected rather than ignored, so it dead-letters instead of silently dropping a signal. - Status updates need not arrive in order, and may be skipped. ChronosHub advances a check monotonically, so a late
RECEIVEDafter aPROCESSINGis discarded rather than regressing it. - The
reportIdexists only once the report is generated.RECEIVEDnever carries one, andPROCESSINGorFAILEDmay omit it or send null. ChronosHub keeps the lastreportIdit has seen. - Extra properties are tolerated. The report-generated payload carries a top-level
statusofSUCCESS, which ChronosHub ignores; the event type already conveys it. Ofdata.metadata, onlyreport_linkis stored. - Two report ids. The sample's
data.metadata.report_iddiffers from the top-levelreportId. ChronosHub records the top-level one. fileUrlis time-limited, so it must be fetched before it expires.- An inbound event whose
correlationIdmatches no known check is acknowledged and ignored; it does not corrupt the manuscript's record.