Skip to main content
ONVY webhooks let your integration react to changes without polling.

Configuration shape

Webhook delivery is configured per project:
{
  "url": "https://customer.example/webhooks/onvy",
  "events": ["users:created", "daily_records:updated", "ai_summaries:created"],
  "enabled": true,
  "hmac_secret": "replace-with-a-secret-of-at-least-16-characters"
}
Rules:
  • url must be HTTPS
  • events must contain only supported event names
  • enabled must be true to send deliveries
  • hmac_secret must be at least 16 characters

Delivery payload

One POST can contain multiple matching events:
{
  "id": "wh_01J...",
  "created_at": "2026-03-05T18:10:27Z",
  "project_id": "proj_123",
  "org_id": "org_123",
  "api_version": 1,
  "events": [
    {
      "name": "daily_records:updated",
      "user_id": "user_123",
      "data": {
        "id": "score_123"
      }
    }
  ]
}

Headers

  • X-Webhook-Signature
  • X-Webhook-Timestamp
  • X-Webhook-ID
The signature uses HMAC-SHA256 and the format sha256=<hex_digest>.

Verify signatures

import hashlib
import hmac


def verify_signature(raw_body: bytes, secret: str, header_value: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode("utf-8"),
        raw_body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, header_value)

Event families

The current public webhook catalog includes:
  • users:*
  • facts:*
  • daily_records:*
  • ai_summaries:*
  • custom_records:*
  • workouts:*
  • lab_tests:*
  • meals:*
  • Batch lifecycle events such as batch.succeeded
Use the exact event names supported by your project configuration.