Arcova Docs

Developers

Webhooks

Outbound webhook delivery contract, headers, payload keys, and currently supported event types.

Overview

Webhook contract

Webhooks deliver real-time events when incidents, shifts, or other resources change. Default environment is sandbox.

FieldValue
Sourcewebhook-fixture-dispatch-contract
Signature algorithmhmac-sha256
Sandbox endpointhttps://sandbox.example.com/webhooks/arcova
Production endpointhttps://api.example.com/webhooks/arcova
Sandbox secret prefixwhsec_sandbox_
Production secret prefixwhsec_live_

Use production webhook secrets only after sandbox deliveries and signature verification checks pass.

Reference

Headers and payload

Required headers

  • Content-Type
  • X-Webhook-Signature
  • X-Webhook-Timestamp
  • X-Webhook-Event
  • X-Webhook-Id
  • X-Idempotency-Key

Required payload keys

  • event
  • timestamp
  • timestamp_iso
  • webhook_id
  • idempotency_key
  • data

Example payload (incident.created)

{
  "id": "evt_abc123def456",
  "type": "incident.created",
  "created_at": 1700000000,
  "data": {
    "object": {
      "id": "inc_xyz789",
      "location_id": "loc_123",
      "location_name": "Main Office Building",
      "status": "open",
      "priority": "high",
      "reported_by": "John Smith",
      "created_at": "2024-01-15T10:30:00Z",
      "updated_at": "2024-01-15T10:30:00Z"
    },
    "previous_attributes": null
  }
}

Reference

Event types

EventDescription
webhook.testTest event
employee.createdCreated event
employee.updatedUpdated event
employee.terminatedTerminated event
shift.createdCreated event
shift.updatedUpdated event
shift.cancelledCancelled event
shift.assignedAssigned event
shift.unassignedUnassigned event
timeentry.clockinClockin event
timeentry.clockoutClockout event
invoice.createdCreated event
invoice.sentSent event
invoice.paidPaid event
invoice.overdueOverdue event
invoice.voidedVoided event
payment.receivedReceived event
payment.failedFailed event
payment.refundedRefunded event
operations.incident_createdIncident Created event
operations.incident_updatedIncident Updated event
operations.incident_resolvedIncident Resolved event
operations.dispatch_createdDispatch Created event
operations.dispatch_assignedDispatch Assigned event
operations.dispatch_completedDispatch Completed event
compliance.credential_expiringCredential Expiring event
client.createdCreated event
client.updatedUpdated event
contract.createdCreated event
contract.renewedRenewed event
contract.expiringExpiring event
training.student_createdStudent Created event
training.student_updatedStudent Updated event
training.student_verifiedStudent Verified event
training.enrollment_createdEnrollment Created event
training.enrollment_confirmedEnrollment Confirmed event
training.enrollment_completedEnrollment Completed event
training.enrollment_cancelledEnrollment Cancelled event
training.enrollment_refundedEnrollment Refunded event
training.class_createdClass Created event
training.class_updatedClass Updated event
training.class_startedClass Started event
training.class_completedClass Completed event
training.class_cancelledClass Cancelled event
training.class_rescheduledClass Rescheduled event
training.class_unpublishedClass Unpublished event
training.class_deletedClass Deleted event
training.certificate_issuedCertificate Issued event
training.certificate_expiredCertificate Expired event
training.certificate_revokedCertificate Revoked event
training.attendance_checkinAttendance Checkin event
training.attendance_checkoutAttendance Checkout event
training.attendance_missedAttendance Missed event

Behavior

Delivery and retries

Webhooks are retried automatically when your endpoint returns a non-2xx response or times out. Treat delivery as best-effort — design your handler to be idempotent.

Retry schedule

AttemptDelay
1Immediate
21 minute
35 minutes
415 minutes
51 hour
66 hours
712 hours
  • Timeout: 30 seconds per attempt.
  • Max attempts: 7 (gives up after ~24 hours).
  • Idempotency: theX-Idempotency-Keyheader lets you detect duplicates safely.

Security

Signature format

The X-Webhook-Signature header carries a timestamp and a signature in a structured format.

X-Webhook-Signature: t=1700000000,v1=a1b2c3d4e5f6...

Format: t=<unix-timestamp>,v1=<hex-signature>

Components:
- t:  Unix timestamp when signature was created
- v1: HMAC-SHA256 signature of "timestamp.raw_body" using webhook secret

Verification steps

  1. Extract t and v1 from the header.
  2. Reject if the timestamp is older than 5 minutes (replay protection).
  3. Construct the signed payload: timestamp + "." + raw_request_body.
  4. Compute HMAC-SHA256 using your webhook secret.
  5. Compare the computed signature to v1 using constant-time comparison.

Patterns

Idempotency

Handle duplicate deliveries safely by storing theX-Idempotency-Keyyou have already processed for at least 24 hours.

// Example: deduplicate using X-Idempotency-Key
const idempotencyKey = headers['x-idempotency-key'];

if (await processedWebhooks.has(idempotencyKey)) {
  // Already processed — return 200 to stop retries
  return res.status(200).send('OK');
}

await processEvent(payload);
await processedWebhooks.add(idempotencyKey);

return res.status(200).send('OK');

Examples

Verification snippets

Sandbox (https://sandbox.example.com/webhooks/arcova)

const timestamp = headers["X-Webhook-Timestamp"];
const signatureHeader = headers["X-Webhook-Signature"];
const signedPayload = timestamp + "." + rawBody;
const expected = crypto
  .createHmac("sha256", "whsec_sandbox_your_secret")
  .update(signedPayload)
  .digest("hex");

Production (https://api.example.com/webhooks/arcova) — intentional switch only

Use production webhook secrets only after sandbox deliveries and signature verification checks pass.

const timestamp = headers["X-Webhook-Timestamp"];
const signatureHeader = headers["X-Webhook-Signature"];
const signedPayload = timestamp + "." + rawBody;
const expected = crypto
  .createHmac("sha256", "whsec_live_your_secret")
  .update(signedPayload)
  .digest("hex");