Appearance
Outbound Events
Outbound events allow you to receive notifications from ChronosHub when something happens that is relevant to your integration (e.g., a manuscript was submitted). ChronosHub delivers these events to your webhook endpoint as signed HTTP POST requests.
To receive outbound events, you need a webhook URL and a webhook secret, both configured during onboarding.
How It Works
- An event occurs in ChronosHub that matches one of your subscribed event types.
- ChronosHub signs the payload with your webhook secret and sends a
POSTrequest to your webhook URL. - Your endpoint processes the event and responds with a
2xxstatus code to confirm receipt. - If delivery fails, ChronosHub retries automatically.
Prerequisites
The following are configured by ChronosHub during onboarding:
| Item | Description |
|---|---|
| Webhook URL | The HTTPS endpoint where ChronosHub will POST events. |
| Webhook Secret | A shared secret used to sign webhook payloads so you can verify their authenticity. |
| Event Subscriptions | The event types you want to receive (e.g., manuscript.submitted). |
Webhook Request Format
ChronosHub sends a POST request to your webhook URL with the following headers and body.
Headers
| Header | Description |
|---|---|
Content-Type | application/json |
User-Agent | ChronosHub-Integration-Framework/1.0 |
X-Hub-Signature-256 | HMAC-SHA256 signature of the request, prefixed with sha256=. Used for verification. |
X-Event-Type | The type of event (e.g., manuscript.submitted). |
X-Event-Id | Unique identifier for this event (UUID). |
X-Timestamp | Unix timestamp (seconds) when the request was signed. |
Body
The request body is a JSON payload containing the event data. The exact shape depends on the event type agreed upon during onboarding.
Example Request
http
POST /webhook HTTP/1.1
Host: partner.example.com
Content-Type: application/json
User-Agent: ChronosHub-Integration-Framework/1.0
X-Hub-Signature-256: sha256=a1b2c3...
X-Event-Type: manuscript.submitted
X-Event-Id: d4e5f6a7-b8c9-0123-4567-89abcdef0123
X-Timestamp: 1740000000
{
"manuscriptId": "MS-2026-001",
"title": "Example Manuscript",
"submittedAt": "2026-02-26T12:00:00Z"
}Expected Response
Your endpoint should return a 2xx status code to acknowledge receipt. The response body is ignored by ChronosHub.
| Status | Meaning |
|---|---|
200 OK / 202 Accepted | Event received successfully. |
| Any non-2xx | Delivery is considered failed and will be retried. |
Retry Behavior
If delivery fails (non-2xx response or network error), ChronosHub retries the delivery up to 5 times. Events that still fail after all retries are marked as failed. If you experience persistent delivery failures, contact your ChronosHub onboarding contact for assistance.
Redirects and webhook targets
These rules apply to sandbox partners, the outside developers who use the test environment.
For regular partners, delivery is unchanged: the HTTP client follows redirects with its default behaviour, so a 301, 302 or 303 can turn the POST into a GET. Register the final URL and do not rely on redirects. See Receiving Webhooks.
Sandbox partners:
- ChronosHub follows only
307and308redirects, at most 5 hops, and only to HTTPS locations. A301,302or303response fails the delivery. - Webhook hosts that resolve to private, loopback, link-local, CGNAT, unique-local or multicast addresses are rejected when the webhook is configured, and fail at delivery.
- The target is checked on every hop, so a redirect to a blocked address fails the delivery.
Signature Verification
Every webhook request is signed using HMAC-SHA256 with your webhook secret. You should verify the signature before processing the event to confirm the request came from ChronosHub and was not tampered with. Receiving Webhooks has verified examples in C#, Node.js, Python and Java.
Verification Steps
Read the raw request body as a UTF-8 string.
Build the signature message using the following length-prefixed format:
{payload_length}:{payload}|{event_type}|{event_id}|{timestamp}Where:
{payload_length}— the length of the raw payload string in UTF-16 code units (String.Lengthin C#,lengthin Java and JavaScript). Characters outside the Basic Multilingual Plane, such as emoji, count as two.{payload}— the raw request body.{event_type}— the value of theX-Event-Typeheader.{event_id}— the value of theX-Event-Idheader.{timestamp}— the value of theX-Timestampheader.
Compute the HMAC-SHA256 hash of the message using your webhook secret as the key.
Compare the resulting hex digest (lowercase) with the value after the
sha256=prefix in theX-Hub-Signature-256header.
Example (Python)
python
import hmac
import hashlib
def verify_signature(payload: str, secret: str, event_type: str, event_id: str, timestamp: str, received_signature: str) -> bool:
payload_length = len(payload.encode("utf-16-le")) // 2 # UTF-16 code units, not Python code points
message = f"{payload_length}:{payload}|{event_type}|{event_id}|{timestamp}"
expected = hmac.new(secret.encode(), message.encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, received_signature.removeprefix("sha256="))Example (C#)
csharp
using System.Security.Cryptography;
using System.Text;
bool VerifySignature(string payload, string secret, string eventType, string eventId, string timestamp, string receivedSignature)
{
var message = $"{payload.Length}:{payload}|{eventType}|{eventId}|{timestamp}";
var keyBytes = Encoding.UTF8.GetBytes(secret);
var messageBytes = Encoding.UTF8.GetBytes(message);
var hash = HMACSHA256.HashData(keyBytes, messageBytes);
var expected = Convert.ToHexString(hash).ToLowerInvariant();
return CryptographicOperations.FixedTimeEquals(
Encoding.UTF8.GetBytes(expected),
Encoding.UTF8.GetBytes(receivedSignature.Replace("sha256=", "")));
}Event Types
Event types are dot-separated identifiers that describe what happened (e.g., manuscript.submitted). You only receive events for the types you are subscribed to. Subscriptions are configured during onboarding.