careCycle
Webhooks

Webhooks

Receive real-time careCycle events at your own HTTPS endpoints.

Webhooks let careCycle push events to your systems the moment they happen — when a customer is created or updated, or when a call finishes — so you can keep a CRM in sync, trigger downstream automations, or build your own reporting without polling the API.

Each event is delivered as a signed POST request to the endpoint(s) you register. careCycle only sends events to clients that have configured at least one endpoint, so there's nothing to opt out of if you don't use webhooks.

Setting up webhooks

Webhooks are managed from Developer Settings → Webhooks in the dashboard.

Enable webhooks

Go to the Webhooks page and click Get started. This provisions webhook delivery for your organization.

Add an endpoint

Click Add Endpoint, enter the HTTPS URL that should receive events, and optionally choose which events to subscribe to. Leave the event selection empty to receive every event type.

Verify delivery

Trigger an event (for example, update a customer) and open the endpoint to see the delivery under Message attempts. Click into any message to inspect the payload, the response your endpoint returned, and the request headers.

Endpoint URLs must be publicly reachable over HTTPS. You can use a tool like webhook.site to experiment before pointing webhooks at your own service.

Verifying signatures

Every request includes signature headers so you can confirm it genuinely came from careCycle and was not tampered with:

HeaderDescription
svix-idUnique identifier for the message
svix-timestampUnix timestamp (seconds) of the send
svix-signatureSpace-delimited list of HMAC-SHA256 signatures

Each endpoint has its own Signing Secret (prefixed with whsec_), visible on the endpoint's detail page. Verify the signature over the raw request body before trusting a payload. The signing scheme is the open Standard Webhooks spec, so you don't have to implement HMAC verification by hand — an official library does it for you.

Get the verification library

careCycle signs with the same scheme Svix uses, so the maintained svix libraries work directly. They're published on each language's standard package registry under the name svix (the standardwebhooks libraries are byte-for-byte compatible if you prefer the vendor-neutral name):

npm install svix
# or: pnpm add svix / yarn add svix
pip install svix
go get github.com/svix/svix-webhooks/go
gem install svix
composer require svix/svix
cargo add svix

Verify an incoming request

Pass the raw request body and the three svix-* headers to the library. It recomputes the HMAC with your signing secret and throws / returns an error if the signature doesn't match. On success you get the verified payload back.

import { Webhook } from "svix"

const wh = new Webhook(process.env.CARECYCLE_WEBHOOK_SECRET) // whsec_...

// `payload` MUST be the raw request body string, not the parsed object.
const event = wh.verify(payload, {
  "svix-id": req.headers["svix-id"],
  "svix-timestamp": req.headers["svix-timestamp"],
  "svix-signature": req.headers["svix-signature"],
})
from svix.webhooks import Webhook

wh = Webhook(os.environ["CARECYCLE_WEBHOOK_SECRET"])  # whsec_...

# `payload` is the raw request body (bytes or str), not the parsed dict.
event = wh.verify(payload, {
    "svix-id": request.headers["svix-id"],
    "svix-timestamp": request.headers["svix-timestamp"],
    "svix-signature": request.headers["svix-signature"],
})
import svix "github.com/svix/svix-webhooks/go"

wh, err := svix.NewWebhook(os.Getenv("CARECYCLE_WEBHOOK_SECRET")) // whsec_...
if err != nil {
    return err
}

// `body` is the raw request body bytes. `r.Header` carries the svix-* headers.
if err := wh.Verify(body, r.Header); err != nil {
    http.Error(w, "invalid signature", http.StatusBadRequest)
    return
}
require "svix"

wh = Svix::Webhook.new(ENV["CARECYCLE_WEBHOOK_SECRET"]) # whsec_...

# `payload` is the raw request body string.
json = wh.verify(payload, {
  "svix-id" => request.headers["svix-id"],
  "svix-timestamp" => request.headers["svix-timestamp"],
  "svix-signature" => request.headers["svix-signature"],
})
use Svix\Webhook;

$wh = new Webhook(getenv("CARECYCLE_WEBHOOK_SECRET")); // whsec_...

// $payload is the raw request body string.
$json = $wh->verify($payload, [
    "svix-id" => $_SERVER["HTTP_SVIX_ID"],
    "svix-timestamp" => $_SERVER["HTTP_SVIX_TIMESTAMP"],
    "svix-signature" => $_SERVER["HTTP_SVIX_SIGNATURE"],
]);
use svix::webhooks::Webhook;

let wh = Webhook::new(&secret)?; // whsec_...

// `body` is the raw request body bytes; `headers` is the http::HeaderMap.
wh.verify(&body, &headers)?;

Verify against the raw, unparsed request body. Re-serializing the JSON before verifying will change the bytes and the signature check will fail — most web frameworks parse JSON automatically, so reach for the raw-body accessor (e.g. express.raw(), await request.body(), request.get_data()).

Delivery, retries, and replay

  • Respond quickly with a 2xx. Any 2xx status is treated as success. Do your heavy processing asynchronously and acknowledge fast.
  • Failed deliveries are retried automatically with exponential backoff.
  • Replay anytime. From the endpoint or message detail page you can replay an individual delivery — useful after fixing an outage on your side.
  • Order is not guaranteed. Use the event payload (and svix-id for idempotency) rather than assuming events arrive in the order they occurred.

Next, see the full list of events and example payloads.

On this page