Configuring webhooks
All three source connectors deliver real-time updates through a single endpoint on your Moʻolelo deployment. This page covers what that endpoint expects, how signatures are verified, and how to manage the secrets.
The webhook URL
Each delivery hits:
https://<your-moolelo-host>/webhooks/<provider>/<instance>Where:
<provider>isgithub,confluence, orsharepoint.<instance>is the same string you used in theconnector_configsrow'sinstancecolumn.
For example, if your deployment is at search.moolelo.example and you configured the GitHub connector with instance = 'acme', the GitHub webhook URL is:
https://search.moolelo.example/webhooks/github/acmeThe webhook URL must be reachable from the source system's outbound IP ranges. For SaaS sources this means a public-internet HTTPS endpoint; for self-hosted sources (GitHub Enterprise Server, Confluence Data Center) it can be a private endpoint reachable from the source's network.
Signature verification
| Provider | Mechanism | Header / field | Algorithm |
|---|---|---|---|
| GitHub | HMAC over body | X-Hub-Signature-256: sha256=<hex> | HMAC-SHA256 |
| Confluence | HMAC over body | X-Hub-Signature: sha256=<hex> | HMAC-SHA256 |
| SharePoint (Microsoft Graph) | Per-notification clientState match | value[].clientState field in body | constant-time string equality |
Every delivery is verified on receipt. Unsigned, wrongly-signed, or missing-signature deliveries are rejected with HTTP 401.
For SharePoint specifically, the authentication model is different. Microsoft Graph doesn't HMAC-sign notifications; instead, you provide a clientState secret when creating a subscription, and Graph echoes it back inside each notification. Moʻolelo constant-time-compares the echoed clientState against the configured secret.
Secret management
Each provider has a single secret value the webhook receiver checks. The values are configured via environment variables on the webhook receiver service:
| Variable | Used for |
|---|---|
WEBHOOK_INGRESS_GITHUB_SECRET | All GitHub webhook deliveries |
WEBHOOK_INGRESS_CONFLUENCE_SECRET | All Confluence webhook deliveries |
WEBHOOK_INGRESS_SHAREPOINT_SECRET | All SharePoint subscription notifications |
In Helm-deployed clusters the secrets come from a Kubernetes Secret named webhook-ingress-secrets. Operators usually wire this from HashiCorp Vault via External Secrets Operator so the values rotate without redeployment.
Because each provider has one secret across all instances, every webhook on a given provider uses the same secret. (Per-instance secrets are a future enhancement.)
The Microsoft Graph subscription handshake
When you create a SharePoint subscription, Microsoft Graph POSTs your webhook URL with a ?validationToken=<random> query parameter and an empty body. Your webhook URL must echo the token in the response body, in plaintext, within 10 seconds.
Moʻolelo's webhook receiver does this automatically on the POST /webhooks/sharepoint/<instance>?validationToken=... path. You don't have to do anything — but be aware:
- Network latency on your side counts toward the 10-second budget.
- TLS termination in front of the receiver counts.
- If you put a CDN in front that buffers request bodies, the handshake will fail.
For internal-only (self-hosted) Microsoft Graph webhook setups, the same handshake applies; you just need internal DNS + private connectivity.
Health checks
The webhook receiver exposes:
GET /healthz— liveness; returns 200 once the process is up.GET /readyz— readiness; returns 200 once the receiver is ready to accept deliveries.
Use these in your Kubernetes readiness probe and external monitoring.
Delivery retry semantics
Each source has its own retry policy when your webhook endpoint fails:
- GitHub — retries 3 times with exponential backoff, then gives up. Failed deliveries are visible in the GitHub repository's webhook delivery log; you can manually redeliver from there.
- Confluence — retries up to 5 times over ~24 hours. After that, the delivery is dropped. You can recapture missed periods by toggling the connector's
modetobackfillinconnector_configs. - Microsoft Graph (SharePoint) — retries up to 4 hours, with backoff. After that, missed notifications are gone — you're expected to resync via a delta query.
In all three cases, Moʻolelo's connector backfill mode covers any gaps without re-indexing already-known records, so a brief outage is recoverable.
Multiple instances per provider
If you connect two GitHub orgs (e.g., acme and acme-eu) to the same Moʻolelo deployment, the webhook URLs are distinct:
https://search.moolelo.example/webhooks/github/acme
https://search.moolelo.example/webhooks/github/acme-euBut the secret is shared across instances of the same provider. If you need per-instance secrets (typically for compliance reasons), run separate webhook receivers — Helm makes this a values-file change, not a code change.
Troubleshooting
- All webhooks 401. The configured secret doesn't match what the source has. Re-paste the secret on the source side; for GitHub, the per-repository secret is independent of any other repository's.
- All webhooks 501. The provider isn't enabled on the receiver. Check
WEBHOOK_INGRESS_PROVIDERSincludes the provider name. - GitHub webhook delivery delayed by minutes. GitHub webhooks are at-least-once and best-effort; large repositories can occasionally take a few minutes during incidents on GitHub's side. Your connector backfill catches up if a delivery is dropped entirely.
- SharePoint subscription expires. Drive-item subscriptions max out at ~60 minutes per Microsoft Graph's policy. You need an operator-side scheduler that calls
PATCH /subscriptions/<id>to renew. This isn't something Moʻolelo handles automatically today.

