# 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-Signature` header. The signature must be computed as `sha256=` 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 (`RateLimitRequests` over `RateLimitWindowSeconds`). * Requests over the limit return `429` and include a `Retry-After` header. * Defaults: 120 requests / 60 seconds. Adjust via configuration. * Outside the `Testing` environment, the limiter is distributed and backed by the existing `scheduler:queue` Redis transport contract. `InMemoryWebhookRateLimiter` remains test-only. * If either inbound webhook remains enabled outside `Testing` without `scheduler:queue.kind=Redis` and 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.