Sprint SPRINT_20260417_019_JobEngine_truthful_webhook_rate_limiter_runtime. NoOpWebhookRateLimiter + RedisWebhookRateLimiter, service-collection wiring, WebhookRateLimiterRuntimeTests, SCHED-WEB-16-104-WEBHOOKS doc. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2.4 KiB
2.4 KiB
SCHED-WEB-16-104 · Conselier/Excitor Webhook Endpoints
Overview
Scheduler.WebService exposes inbound webhooks that allow Conselier and Excitor to notify the planner when new exports are available. Each webhook validates the payload, enforces signature requirements, and applies a per-endpoint rate limit before queuing downstream processing.
| Endpoint | Description | AuthZ |
|---|---|---|
POST /events/conselier-export |
Ingest Conselier export metadata (exportId, changedProductKeys, optional KEV & window). |
HMAC X-Scheduler-Signature and/or mTLS client certificate |
POST /events/excitor-export |
Ingest Excitor export delta summary (changedClaims). |
HMAC X-Scheduler-Signature and/or mTLS client certificate |
Security
- Webhooks require either:
- mTLS with trusted client certificates; or
- an HMAC-SHA256 signature in the
X-Scheduler-Signatureheader. The signature must be computed assha256=<hex>over the raw request body.
- Requests without the required signature/certificate return
401. - Secrets are configured under
Scheduler:Events:Webhooks:{Conselier|Excitor}:HmacSecret.
Rate limiting
- Each webhook enforces a sliding-window limit (
RateLimitRequestsoverRateLimitWindowSeconds). - Requests over the limit return
429and include aRetry-Afterheader. - Defaults: 120 requests / 60 seconds. Adjust via configuration.
- Outside the
Testingenvironment, the limiter is distributed and backed by the existingscheduler:queueRedis transport contract.InMemoryWebhookRateLimiterremains test-only. - If either inbound webhook remains enabled outside
Testingwithoutscheduler:queue.kind=Redisand a Redis connection string, Scheduler startup fails fast instead of falling back to process-local rate limiting.
Configuration
Scheduler:
Events:
Webhooks:
Conselier:
Enabled: true
HmacSecret: conselier-secret
RequireClientCertificate: false
RateLimitRequests: 120
RateLimitWindowSeconds: 60
Excitor:
Enabled: true
HmacSecret: excitor-secret
RequireClientCertificate: false
queue:
kind: Redis
redis:
connectionString: localhost:6379
database: 0
Response envelope
On success the webhook returns 202 Accepted and a JSON body:
{ "status": "accepted" }
Failures return problem JSON with error describing the violation.