Webhooks

In this guide, we will look at how to register and consume webhooks to integrate your app with Forms Live. With webhooks, your app can know when something happens in Forms Live, such as when a form is finalised, signed, or when a user template is updated.

Registering webhooks

To register a new webhook, you need to have a URL in your app that Forms Live can call. You can configure a new webhook via the API, specifying the events you want to listen for, and providing your URL.

The webhook system will attempt to POST to your supplied URI up to 3 times before giving up. Your webhook URI must respond with a 200 OK status within 5 seconds to successfully acknowledge the webhook.

Example webhook creation

{
  "active": true,
  "events": ["form.finalise", "form.sign"],
  "uri": "https://webhook.yourdomain.com/endpoint",
  "form_id": null
}

Now, whenever something of interest happens in your app, a webhook is fired off by Forms Live. In the next section, we'll look at how to manage webhooks.

Managing webhooks

Forms Live provides a comprehensive set of endpoints to manage your webhooks:

  1. List all webhooks: Retrieve all webhooks configured for your account
  2. Get a single webhook: Retrieve details about a specific webhook
  3. Create a webhook: Register a new webhook with your desired events and URL
  4. Update a webhook: Modify an existing webhook's configuration
  5. Delete a webhook: Remove a webhook when it's no longer needed

Validating a webhook

Every webhook request from Forms Live is signed so you can confirm it came from us and was not altered in transit. The signature is sent in the Formslive-Signature header in the following format:

Formslive-Signature header

Formslive-Signature: t=1725840000000,sha256=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
  • t is the time the signature was generated, in milliseconds since the Unix epoch.
  • sha256 is a hex-encoded HMAC-SHA256 digest.

The signing secret is your API key, the same key used to build your Authorization header (see Authentication). Keep it on your server and never expose it in client-side code.

To validate a request:

  1. Read the Formslive-Signature header and extract the t and sha256 values.
  2. Take the raw request body exactly as received, before parsing it as JSON. Re-serialising the body will change the bytes and the signature will not match.
  3. Build the signed string by joining the timestamp and the raw body with a full stop: {t}.{raw body}.
  4. Compute the HMAC-SHA256 of the signed string using your API key as the secret, and hex-encode the result.
  5. Compare your digest to the sha256 value using a constant-time comparison. If they differ, reject the request.
  6. Check that t is within an acceptable tolerance of the current time to guard against replay. We recommend five minutes. Retried deliveries reuse the original signature and timestamp, so a tolerance of only a few seconds will reject legitimate retries.

If the signature and timestamp are both valid, the request is authentic. The id in the request body uniquely identifies the delivery and is the same across retries, so use it to de-duplicate events you have already processed.


Event types

  • Name
    form.create
    Description

    A new form was created.

  • Name
    form.finalise
    Description

    A form was finalised.

  • Name
    form.sign
    Description

    A form was signed.

  • Name
    form.executed
    Description

    The was signed by the last signer.

  • Name
    form.update
    Description

    A form was updated.

  • Name
    form.delete
    Description

    A form was successfully deleted.

  • Name
    user_template.create
    Description

    A new user template was created.

  • Name
    user_template.update
    Description

    An existing user template was updated.

  • Name
    user_template.delete
    Description

    A user template was successfully deleted.

Example payload

{
  "id": "7a8b9c0d1e2f",
  "type": "form.finalise",
  "payload": {
    "id": 123,
    "template_version_id": 456,
    "agency_id": 789,
    "user_id": 101,
    "name": "Property Lease Agreement",
    "template": false,
    "finalised": true,
    "private": false,
    "created": 1506294669,
    "updated": 1506294769,
    "given_name": "John",
    "surname": "Smith",
    "template_cost": 80,
    "template_id": 202,
    "template_name": "Residential Lease Agreement",
    "template_code": "RLA2023",
    "template_instruction_pages": 1
  }
}

Webhook endpoints

List all webhooks

This endpoint allows you to retrieve a list of all webhooks configured for your account.

Request

GET
/webhooks/
curl https://app-api.formslive.com.au/webhooks/ \
  --request GET \
  --header "Authorization: Basic YTlkOWIwYItNGY4Yi1hYTQxLTI5NzZmMTcyZmEyMQ=="

Response

[
  {
    "id": 1,
    "active": true,
    "events": ["form.finalise", "form.sign"],
    "uri": "https://webhook.yourdomain.com/endpoint",
    "form_id": null
  },
  {
    "id": 2,
    // ...
  }
]

Get a single webhook

This endpoint allows you to retrieve a specific webhook by providing its ID.

Request

GET
/webhooks/1
curl https://app-api.formslive.com.au/webhooks/1 \
  --request GET \
  --header "Authorization: Basic YTlkOWIwYItNGY4Yi1hYTQxLTI5NzZmMTcyZmEyMQ=="

Response

{
  "id": 1,
  "active": true,
  "events": ["form.finalise", "form.sign"],
  "uri": "https://webhook.yourdomain.com/endpoint",
  "form_id": null
}

Create a webhook

This endpoint allows you to register a new webhook for specific events.

Required attributes

  • Name
    events
    Type
    array
    Description

    Array of event types to listen for.

  • Name
    uri
    Type
    string
    Description

    The URL that Forms Live will POST webhook data to.

Optional attributes

  • Name
    active
    Type
    boolean
    Description

    Whether the webhook should be active. Default is true.

  • Name
    form_id
    Type
    integer
    Description

    If the webhook is for a specific form, specify the form ID.

  • Name
    user_template_id
    Type
    integer
    Description

    If the webhook is for a specific user template, specify the user template ID.

Request

POST
/webhooks/
curl https://app-api.formslive.com.au/webhooks/ \
  --request POST \
  --header "content-type: application/json" \
  --header "Authorization: Basic YTlkOWIwYItNGY4Yi1hYTQxLTI5NzZmMTcyZmEyMQ==" \
  --data '{"active": true, "events": ["form.finalise"], "uri": "https://webhook.yourdomain.com/endpoint"}'

Response

{
  "id": 1,
  "active": true,
  "events": ["form.finalise"],
  "uri": "https://webhook.yourdomain.com/endpoint",
  "form_id": null
}

Update a webhook

This endpoint allows you to update an existing webhook's configuration.

Optional attributes

  • Name
    events
    Type
    array
    Description

    Array of event types to listen for.

  • Name
    uri
    Type
    string
    Description

    The URL that Forms Live will POST webhook data to.

  • Name
    active
    Type
    boolean
    Description

    Whether the webhook should be active.

  • Name
    form_id
    Type
    integer
    Description

    If the webhook is for a specific form, specify the form ID.

  • Name
    user_template_id
    Type
    integer
    Description

    If the webhook is for a specific user template, specify the user template ID.

Request

PUT
/webhooks/1
curl https://app-api.formslive.com.au/webhooks/1 \
  --request PUT \
  --header "content-type: application/json" \
  --header "Authorization: Basic YTlkOWIwYItNGY4Yi1hYTQxLTI5NzZmMTcyZmEyMQ==" \
  --data '{"active": false, "events": ["form.finalise", "form.sign"]}'

Response

{
  "id": 1,
  "active": false,
  "events": ["form.finalise", "form.sign"],
  "uri": "https://webhook.yourdomain.com/endpoint",
  "form_id": null
}

Delete a webhook

This endpoint allows you to delete a webhook when it's no longer needed.

Request

DELETE
/webhooks/1
curl https://app-api.formslive.com.au/webhooks/1 \
  --request DELETE \
  --header "Authorization: Basic YTlkOWIwYItNGY4Yi1hYTQxLTI5NzZmMTcyZmEyMQ=="

Response

{
  "message": "The webhook was successfully deleted."
}

Reliability and best practices

When implementing webhooks with Forms Live, consider the following best practices:

  1. Quick responses: Your webhook endpoint should respond with a 200 OK status quickly (within 5 seconds) to acknowledge receipt
  2. Idempotency: Design your webhook handler to be idempotent, as the same webhook might be delivered multiple times in case of retries
  3. Validation: Verify the Formslive-Signature header on every request, as described in Validating a webhook
  4. Async processing: Acknowledge the webhook quickly, then process the data asynchronously if needed
  5. Logging: Maintain logs of received webhooks for debugging purposes

By following these best practices, you'll ensure a robust integration with Forms Live's webhook system.