Skip to content

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 ​

  1. An event occurs in ChronosHub that matches one of your subscribed event types.
  2. ChronosHub signs the payload with your webhook secret and sends a POST request to your webhook URL.
  3. Your endpoint processes the event and responds with a 2xx status code to confirm receipt.
  4. If delivery fails, ChronosHub retries automatically.

Prerequisites ​

The following are configured by ChronosHub during onboarding:

ItemDescription
Webhook URLThe HTTPS endpoint where ChronosHub will POST events.
Webhook SecretA shared secret used to sign webhook payloads so you can verify their authenticity.
Event SubscriptionsThe 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 ​

HeaderDescription
Content-Typeapplication/json
User-AgentChronosHub-Integration-Framework/1.0
X-Hub-Signature-256HMAC-SHA256 signature of the request, prefixed with sha256=. Used for verification.
X-Event-TypeThe type of event (e.g., manuscript.submitted).
X-Event-IdUnique identifier for this event (UUID).
X-TimestampUnix 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.

StatusMeaning
200 OK / 202 AcceptedEvent received successfully.
Any non-2xxDelivery 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 307 and 308 redirects, at most 5 hops, and only to HTTPS locations. A 301, 302 or 303 response 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 ​

  1. Read the raw request body as a UTF-8 string.

  2. 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.Length in C#, length in 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 the X-Event-Type header.
    • {event_id} — the value of the X-Event-Id header.
    • {timestamp} — the value of the X-Timestamp header.
  3. Compute the HMAC-SHA256 hash of the message using your webhook secret as the key.

  4. Compare the resulting hex digest (lowercase) with the value after the sha256= prefix in the X-Hub-Signature-256 header.

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.