Skip to content
JARAI Developers

Webhook Integration

Webhooks deliver real-time event notifications to your server, eliminating the need for status polling. JARAI supports 9 event types with at-least-once delivery and HMAC-SHA256 signature verification.

Registering a Webhook

Register an HTTPS endpoint to receive events:

curl -X POST https://api.jarai.studio/v1/webhooks \
-H "X-API-Key: jarai_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
  "endpointUrl": "https://your-server.com/webhooks/jarai",
  "eventTypes": [
    "production.queued",
    "production.step.complete",
    "production.published",
    "production.failed",
    "deliverable.ready"
  ]
}'

The response includes a signingSecret (base64url-encoded). Store it securely — it is returned only on creation and cannot be retrieved again.

Registration Options

Field Required Type Description
endpointUrl Yes string HTTPS URL to receive webhook events. HTTP is not accepted.
eventTypes Yes string[] At least one event type from the supported list.
accountIds No UUID[] Limit events to specific accounts (max 50). Must be a subset of your permitted accounts.
accountScopeId No UUID Limit events to a single account. Mutually exclusive with accountIds.

You can register up to 100 active webhook subscriptions.

Signature Verification

Every webhook delivery includes an X-JARAI-Signature header for verifying authenticity:

X-JARAI-Signature: sha256=a1b2c3d4e5f6...

Verification Algorithm

  1. Read the raw HTTP request body as bytes (do not parse and re-serialize the JSON).
  2. Compute HMAC-SHA256 using your signingSecret (base64url-decoded) as the key and the raw body as the message.
  3. Hex-encode the resulting digest.
  4. Compare with the value after sha256= in the X-JARAI-Signature header using a constant-time comparison to prevent timing attacks.
using System.Security.Cryptography;
using System.Text;

public static bool VerifySignature(
  byte[] requestBody,
  string signatureHeader,
  string signingSecretBase64Url)
{
  // Decode the base64url signing secret
  string base64 = signingSecretBase64Url
      .Replace('-', '+')
      .Replace('_', '/');
  switch (base64.Length % 4)
  {
      case 2: base64 += "=="; break;
      case 3: base64 += "="; break;
  }
  byte[] secret = Convert.FromBase64String(base64);

  // Compute HMAC-SHA256
  using var hmac = new HMACSHA256(secret);
  byte[] hash = hmac.ComputeHash(requestBody);
  string expected = "sha256=" + Convert.ToHexString(hash).ToLowerInvariant();

  // Constant-time comparison
  return CryptographicOperations.FixedTimeEquals(
      Encoding.UTF8.GetBytes(expected),
      Encoding.UTF8.GetBytes(signatureHeader));
}

Important Notes

  • Always verify against the raw request body bytes, not a parsed-and-re-serialized version of the JSON. Re-serialization may alter whitespace or field ordering, breaking the signature.
  • Use constant-time comparison to prevent timing side-channel attacks.
  • If verification fails, return a 4xx status code and do not process the event.

Event Types

JARAI delivers 9 event types. See the Webhook Reference for complete payload schemas and field tables.

Event Type Trigger
production.queued Production submitted to the pipeline.
production.step.complete A pipeline step finished processing.
production.awaiting_approval All pipeline steps complete; waiting for operator release.
production.distributing First platform publication started.
production.published All platforms published successfully.
production.failed Production failed terminally.
production.cancelled Production cancelled by partner or operator.
deliverable.ready Deliverable files are available for download.
webhook.ping Ping test event (no real production data).

Retry Schedule

JARAI uses at-least-once delivery. If your endpoint does not return a 2xx response, the event is retried:

Attempt Timing
1st retry Immediate
2nd retry 1 minute after first failure
3rd retry 5 minutes after second failure

After all three retries fail, the delivery is counted as a failure and the subscription’s failureCount is incremented.

Auto-Suspension

  • At 3 consecutive failures: a WebhookDeliveryFailed warning alert is raised internally.
  • At 10 consecutive failures: the subscription status is set to Failed and no further events are delivered. A WebhookEndpointUnreachable alert is raised.

A successful delivery resets the failure counter to zero.

Reinstating a Suspended Subscription

If your subscription reaches Failed status, reinstate it after fixing your endpoint:

curl -X POST https://api.jarai.studio/v1/webhooks/{subscriptionId}/reinstate \
-H "X-API-Key: jarai_your_api_key_here"

Reinstatement requires self-serve lifecycle operations to be enabled on your partner account. If they are not, the call returns 403 SELF_SERVE_DISABLED — contact JARAI support and they will reinstate the subscription for you.

Testing Webhooks

Send a test event to verify your endpoint is reachable and correctly verifying signatures:

curl -X POST https://api.jarai.studio/v1/webhooks/{subscriptionId}/ping \
-H "X-API-Key: jarai_your_api_key_here"

Ping events deliver a webhook.ping event with productionId and accountId set to nil UUIDs (00000000-0000-0000-0000-000000000000). Pings do not consume your shared RPM budget, but are limited to 1 per subscription per minute.

Idempotency

JARAI guarantees at-least-once delivery, which means you may receive the same event more than once. Use the composite key {productionId}:{sequenceNumber} to deduplicate events. The sequenceNumber is per-production (not globally unique).

Next Steps