Skip to content

Webhooks

Polling, the Tranche 1 default, has a median latency of about 30 seconds. For sub-second propagation — useful when your fleet operates under tight change-control windows — Ampora exposes an inbound webhook endpoint per Git source.

When webhooks help

  • Median sync latency of well under 1 second.
  • Avoids the PollIntervalSeconds race when a fast follow-up commit changes a file before the previous sweep has finished.
  • Keeps the cache cold path identical — webhook fires "go check the tip", the sweeper does the work.

When webhooks do NOT help

  • The Git host cannot reach Ampora over HTTPS (air-gapped, NATted, privately exposed). Polling is the right answer.
  • You have very few configurations; the polling latency is fine.

Endpoint shape

POST https://AMPORA_HOST/api/git/webhook/{sourceId}
Content-Type: application/json
X-Ampora-Webhook-Token: <per-source-secret>

{ /* upstream payload — currently the body is opaque to Ampora */ }

The body is opaque to Ampora today — we do not parse the upstream payload. The webhook is a "go check the tip" signal; the sweeper does the actual work. This means:

  • Any Git host that fires any webhook works (GitLab, GitHub, Gitea, Bitbucket, self-hosted Gitolite, …).
  • Replay-safe: hitting the endpoint many times is idempotent.
  • Tamper-safe: even a faked payload cannot mislead the sweeper — the truth is the Git tree.

The X-Ampora-Webhook-Token header is the per-source secret. Generate it on GitOps → {source} → Webhook → Generate token, copy once, configure the upstream Git host with it.

Configuring on the Git host side

GitLab

Project → Settings → Webhooks:

  • URL: https://AMPORA_HOST/api/git/webhook/{sourceId}
  • Custom HTTP header: X-Ampora-Webhook-Token: <token>
  • Trigger: Push events on the tracked branch only.

GitHub

Repository → Settings → Webhooks → Add webhook:

  • Payload URL: https://AMPORA_HOST/api/git/webhook/{sourceId}
  • Content type: application/json
  • Secret: leave empty (the token goes in a custom header which GitHub does not natively support — use a Webhook Trigger via GitHub Actions if you need to inject the header).

Bitbucket

Repository → Repository settings → Webhooks:

  • URL: https://AMPORA_HOST/api/git/webhook/{sourceId} with the token appended as a query string is acceptable.

Verification

After configuring, push a trivial commit. GitOps → {source} → Sync runs should show a run within a second, attributed to webhook rather than poll.

If nothing happens:

  • the inbound HTTPS endpoint is not reachable from the Git host (firewalls, no public DNS),
  • the token mismatches — the audit log records every 401,
  • the source is paused.

Falling back to polling

Even with webhooks configured, the polling timer still runs at the configured interval (default 60 s) as a backstop. A missed webhook delivery is masked by the next poll.

Rate limits

Ampora does not rate-limit webhooks — every request kicks the same underlying sweep, which deduplicates internally on the tip SHA. Spamming the endpoint a thousand times produces at most one sweep.

Security

  • The token is hashed at rest, constant-time compared on every request.
  • Endpoint requires HTTPS in production (OpAmp:BootstrapPlaintextAllowed=false and friends do not affect the webhook path; production rejects HTTP unconditionally).
  • Per-source token rotation: Webhook → Rotate token invalidates the old token immediately. Update upstream Git host config before rotating to avoid a delivery gap.