Skip to main content



Webhooks are currently only available in certain Hosted CTFd tiers and CTFd Enterprise


Webhooks are HTTP requests sent by CTFd to endpoints you choose when certain events occur within the application. CTFd webhooks go through an initial verification over GET requests and subsequent events are sent over POST requests.


Webhook endpoints are first validated by CTFd to prove that you have ownership over the endpoint. To validate an endpoint, CTFd will send a GET request to the URL with an additional query parameter, "token". Your endpoint must then construct a JSON response containing the token hashed with HMAC-SHA256.

For example with an endpoint of, CTFd will send:


and your application should respond with

{"response": hmac_sha256(SHARED_SECRET, "2b00042f6")}


Events types are specified by the CTFd-Webhook-Event header and the request body will contain the event body. The body will differ based on the event but in general will be the schema specified for the object in the REST API documentation


It's important to ensure that your endpoint verifies that data is coming from CTFd. If not, malicious users could potentially replay requests to your endpoint or trick your endpoint into doing something it isn't supposed to.

CTFd provides the CTFd-Webhook-Signature header on every webhook sent out.

For example:

Ctfd-Webhook-Signature: t=1616995588,v1=9e8cdd253434b74119ff44a119bb2d93e3b78a3a6a1a52d71e1bf70c36c55234

The header is split up into two sections t and v1. t represents the unix time/epoch time when the webhook was sent out. The v1 value represents an HMAC-SHA256 of the the t value, a period, and the request body, with the shared secret as the HMAC key.

For example if your endpoint received a body of {'data': None, 'value': None} then the signature would be made up of hmac_sha256(SHARED_SECRET, "1616995588.{'data': None, 'value': None}")

For optimal security, your endpoint should validate the signature of every request before using any of the data contained within. In addition, your endpoint can also choose to ignore requests whose signature is too old based on the timestamp.

Should an attacker attempt to manipulate the timestamp, request body, or signature, validation should fail as long as your secret hasn't been leaked.


We provide simple applications that implement the above security logic to debug/inspect webhook events:


Questions, feedback, and feature requests can be directed to