Webhook Security Functions

Your webhook listeners can be configured to call one or more security functions before invoking any downstream triggers. Security functions are server functions that will be executed in the order you define them and have the power to reject any incoming webhook event. Each security function will be passed the webhook request body, headers, and parsed params from the url and should return a boolean true value to accept the request, else return a false value to reject the request.

You can configure them directly via the API using the following JSON structure:

{
  "name": "My webhook",
  "securityFunctions": [
    { "id": "yourServerFunctionId", "message": "Message to deliver if this security function flags the request." },
    { "id": "anotherServerFunctionId", "message": "Message to deliver if this security function flags the request." }
  ]
}

Or you can configure within the PolyAPI Web UI:

View of PolyAPI Web UI showing the form for adding/updating security functions on a webhook.

Let’s create a new security function for use in securing the webhook we created in the previous page.

Create a new server function:

async function hasValidCode(
  body: string,
  headers: any,
  params: any
): Promise<any> {
  const event = JSON.parse(body) as { code?: string };
  if (!event || !event.code) return false;
  // Ideally you have authentication secrets stored securely in vari
  // const expected = await vari.test.myWebhookSecret.get();
  // But for an easy demo let's use a hard-coded value:
  const expected = '2hj532kj3k3h4g53';
  if (event.code !== expected) return false;
  return true;
}

And then train this function to poly:

npx poly function add hasValidCode ./src/hasValidCode.ts --server

Now update your webhook to add the security function:

Navigate to the function detail in the Web UI, and click the “Update” button.

At the bottom of the form click the “+ Add” button to add a new security function.

Drop in the id of your new function from when you trained it or search for it in the Web UI picker.

Add an error message for users like: “Invalid or missing ‘code’ in event payload.”

Now let’s save and try out the webhook in the execute UI.

First try to execute the webhook passing an empty event and you’ll see your request is rejected:

View of PolyAPI Web UI showing a webhook execution that has failed to pass through a security function.

Now try adding the secret code to your payload, and when triggered you’ll see the webhook request sails on through as expected.

View of PolyAPI Web UI showing a webhook execution that has successfully passed through a security function.

IP allowlist (DIY)

There is no first-class per-webhook IP allowlist UI. Restrict callers with a security function (runs before triggers).

  1. Read the client IP from headers['x-real-ip'] (set by the edge). Fall back to the first hop in x-forwarded-for only if x-real-ip is absent.

  2. Compare to an allowlist (Vari or a hard-coded list per environment).

  3. Return true to accept, false to reject. Set message on the securityFunctions entry for the reject body.

Do not expect Express-style req.ip. Do not treat a client-supplied header as trusted on a custom proxy you do not control.

CIDR helpers are not a documented public API. Exact-match IPs are the recipe to copy.

Supported request bodies

Send JSON, XML, or other text bodies. application/octet-stream and other raw binary types are not a supported public path. The body often arrives empty in the server function.

Wrap binary as base64 inside JSON ({ "file": "<base64>" }) if you must send bytes.

XML uses the handle’s XML parser options (existing create-form fields). Do not set x-poly-body-encoding yourself; that header is internal.