CAVS publishes internal events to a single Pub/Sub topic. A subset is mapped to
public webhook events; only those ever leave the platform.
The complete list you can subscribe to. See Webhooks .
Public event
Internal event
Fires when
repository.created
repository.created
A repository is created
repository.deleted
repository.deleted
A repository is deleted
repository.push
upload.session.finalized
An upload session is finalized
repository.push.indexed
repository.index.finalized
A Git-index upload is finalized
release.published
repository.release.published
A release appears from a tag
storage.snapshot.created
snapshot.created
A snapshot capture completes
storage.quota.warning
repository.quota.warning
Storage crosses the warning threshold
storage.quota.exceeded
repository.quota.exceeded
Storage exceeds the plan limit
maintenance.gc.completed
gc.completed
A garbage-collection pass completes
"type" : "repository.push" ,
"organization_id" : "0a11bb22-…" ,
"repository_id" : "0f8c3d4e-…" ,
"occurred_at" : "2026-07-28T12:00:04.512Z" ,
"data" : { "session_id" : "3b1f…" , "generation" : 42 }
Treat data as open — new keys can appear. Use it as a pointer and read authoritative
state from the API.
The full set. These drive workers, notifications and the activity feed; unmapped ones
never reach a webhook.
Event
Trigger
user.created
First sign-in
organization.created
An organization is created
organization.member.invited
An invitation is sent → drives the email
organization.member.joined
An invitation is accepted
Event
Trigger
Public
repository.created
Repository created
✓
repository.deleted
Repository deleted
✓
repository.usage.changed
A push finalized → triggers reconciliation
repository.index.finalized
Git-index session finalized
✓
repository.release.published
A tag became a release
✓
repository.quota.warning
Approaching the storage limit
✓
repository.quota.exceeded
Over the storage limit
✓
Event
Trigger
Public
upload.session.created
Session opened
upload.session.finalized
Session finalized
✓ as repository.push
upload.session.failed
Session failed
Event
Trigger
token.created
An API token is created
token.revoked
An API token is revoked
Event
Trigger
Public
snapshot.requested
Snapshot queued
snapshot.created
Snapshot captured
✓
gc.requested
GC requested
gc.completed
GC pass finished
✓
repack.requested
Repack requested
repack.completed
Repack finished
index.compaction.requested
Index compaction requested
index.compaction.completed
Index compaction finished
Event
Trigger
storage.connection.added
A connection is created
storage.connection.tested
The connectivity suite ran
storage.connection.failed
A connection turned unhealthy
storage.connection.restored
A connection recovered
storage.connection.removed
A connection was deleted
Caution
storage.connection.failed means every repository on that connection can’t push or pull
— the bytes are in your bucket and CAVS can’t reach them. Treat it as page-worthy. It
isn’t currently a public webhook event, so watch notifications and email, or
GET …/storage/connections.
Event
Trigger
billing.subscription.updated
Plan or subscription state changed
billing.payment.failed
A payment failed
Event
Trigger
notification.send
Deliver an in-app notification and/or email
audit.event.created
An audit entry was written
Property
Internal (Pub/Sub)
Outbound (webhooks)
Guarantee
at-least-once
at-least-once, 3 attempts
Ordering
per repository, via the ordering key
not guaranteed
Deduplication
processed_events by event id
yours, on X-CAVS-Delivery
Failure
nack and redeliver
logged as a delivery record; circuit breaker at 10 consecutive failures
"event_type" : "upload.session.finalized" ,
"occurred_at" : "2026-07-28T12:00:04Z" ,
event_type is a Pub/Sub message attribute, so consumers can filter without
deserializing. repository_id is the ordering key.
If you self-host and want an internal event exposed to webhooks, add it to the
publicEventName map in the worker. Only mapped events are forwarded — the mapping is
the allowlist, which is what keeps internal detail from leaking.