BETA
Skip to content

Ingest endpoint

POST https://app.krafter.dev/in/:slug

The ingest endpoint is the public-facing URL you give to providers (Stripe, GitHub, Shopify, custom). It accepts unauthenticated POSTs — the provider's signature is the only credential.

The :slug is the auto-generated identifier returned by POST /api/v1/webhooks/sources and exposed to you on the source object as url.

What gets stored

Every accepted POST creates exactly one event row capturing:

  • The resolved event type — extracted from the body or a header per the source's provider configuration.
  • The raw request body (as bytes) and a lowercased headers map.
  • The signature_valid flag (true / false / null).
  • A status of received initially.

Fan-out happens immediately afterwards — see Replay for the lifecycle.

Limits & responses

ConditionHTTP statusBody
Accepted200{"ok":true}
Unknown slug404{"error":"not_found"}
Source's enabled: false410{"error":"source_disabled"}
Body larger than 256 KiB413{"error":"payload_too_large"}
Same slug exceeds 100 requests / second429{"error":"rate_limited"}

The 200 response is returned even when the signature is invalid. The event is stored with signature_valid: false for inspection but not fanned out to destinations. This matches the security model of Stripe and GitHub: never reveal to an attacker whether their forged signature was rejected.

Body parsing

Krafter caches the raw bytes of the request body before Plug.Parsers runs (via KrafterWeb.Plugs.CacheRawBody). HMAC verification always uses those exact bytes — re-serialised JSON would not match the provider's signature.

If the body parses as JSON, it is also stored on the event for use by event_type_path extraction. Non-JSON bodies are stored as-is in raw_body; event_type is then resolved from headers if the source's provider supports it.

Why the ingest URL has no auth

Inbound webhooks don't have access to your Krafter API key — they arrive from a third party. Authentication is therefore purely signature-based:

  1. The provider signs the body using a shared secret.
  2. Krafter recomputes the HMAC and compares it constant-time.
  3. Mismatched signatures result in signature_valid: false and the event is not forwarded. Matched signatures fan out normally.

Without signing_secret configured on the source, every event is stored with signature_valid: nil and not forwarded. Use this mode for one-shot inspection while wiring up a provider for the first time.

Built by Krafter Studio