TurboVote Webhooks

  • Updated

Use incoming webhooks to get real-time updates 

Depending on the terms of your agreement with Democracy Works, you may have access to some of the information users enter into TurboVote.

To learn more or to gain access to TurboVote Webhook events, contact your TurboVote Partner Manager, drop us a line or grab a time to meet.

How to set up your webhook integration

To start receiving webhook events from TurboVote, create a webhook endpoint by following the steps below.

You can create one endpoint to handle several different event types at once, or set up individual endpoints for specific events.

  1. Identify events for which you want to receive webhooks.

  2. Develop a webhook endpoint function to receive POST requests.

  3. Register your endpoint(s) with TurboVote.

  4. Secure your webhook endpoint(s).

1. Identify events for which you want to receive webhooks

We currently support the following events:

Data model

All payloads are JSON-encoded, and are listed below under the corresponding event type.

Field keys will always be included, but may be null if they are not present, which may make it easier to get a sense for fields that are possible.

2. Develop an HTTP endpoint to receive the webhook

You will need to provide TurboVote with a publicly-accessible HTTPS URL in order to receive webhook payloads from us. Webhooks will be sent as a JSON payload (documented above) using the POST method, and the request have a Content-Type of application/json.

You should strive to return a successful HTTP status code (2xx) quickly to avoid any timeouts and subsequent retries. We may adjust the specific timeout value in the future, but a good guideline is to try to return a response in 10 seconds or less. If you have any feedback, please reach out to us.

3. Register your endpoint with TurboVote

When you’re ready to start receiving events, let us know:

  1. Your HTTPS URL

  2. Which events you’d like to receive

We will securely provide you with a signing secret to use if you want to optionally validate the signatures you receive from us, described in Appendix A. Validating signatures is not required if this is an implementation burden for you, but it is a good idea and may be a security requirement in your organization. No matter what you do with the signature, the data we send you will be encrypted in transit using HTTPS.

Appendix A: Validating signatures

The TurboVote-Signature HTTP header included in every request contains a timestamp and one or more signatures to verify. The timestamp is prefixed by t=, and each signature is prefixed by a scheme. Schemes start with v, followed by an integer. Currently, the only valid signature scheme is v1.

TurboVote-Signature:
t=1695137584,
v1=630b33ce05e8ccb2766c6a05339f36b800bd4172cc0d0b0548f4d998668fbcb7,
v1=562664f38b1dff705305460243dbccfdf3f7148208e24664bac9829f5c351c19

Newlines have been added above, but a real TurboVote-Signature header is on a single line.

Additionally, we have provided multiple (two) signatures in order to help you future-proof your implementation, but in practice you will see just one signature (the HMAC prefixed with v1=).

TurboVote generates signatures using a hash-based message authentication code (HMAC) with SHA-256. To prevent downgrade attacks, ignore all schemes that are not v1.

The following steps describe the process for validating a signature:

Step 1: Extract the timestamp and signatures from the header

Split the header using the , character as the separator to get a list of elements. Then split each element using the = character as the separator to get a prefix and value pair.

The value for the prefix t corresponds to the timestamp, and v1 corresponds to the signature (or signatures). You can discard all other elements.

Step 2: Prepare the signed payload

You should create a signed payload string by concatenating the following elements:

  • The timestamp, which is the extracted value of the t parameter from the header, described above

  • The character .

  • The JSON request body, as a string, unchanged from how you received it

For example, the payload string you would construct for signing might look like the following:

1715319123.{"user":{"id":1}}

Step 3: Determine the expected signature

Compute an HMAC with the SHA256 hash function. Use the endpoint’s signing secret as the key, and use the signed payload you generated in Step 2 as the message to be signed.

Step 4: Compare the signatures

Assume you will receive multiple comma-separated signatures, and check the signature you calculated against each provided signature, and avoid processing the request if they all fail to match.

For additional security, check that the timestamp is not older than some time period that you can determine, we suggest 8 hours at most. As a reminder, we will regenerate the timestamp when re-sending failed requests, so older timestamps may indicate a replayed webhook payload or the presence of some other issue, and should be rejected.

It is a good idea to use a constant-time string comparison to compare the expected signature to the received signatures in order to prevent timing attacks.