Skip to main content

Forward a call to a webhook

Create a proxy function so an external endpoint is reachable through the same interface as your other functions.

Prerequisites#

  • An app, and its slug.
  • A public https:// webhook URL that accepts a JSON POST.
  • Any credentials that endpoint requires.

Create the function#

Set execution_mode to proxy and provide webhook_url. Proxy functions carry no code.

  1. Open the app and select Functions.
  2. Select Create Function, then choose the PROXY execution mode.
  3. Enter the webhook URL, then configure authentication and headers.
  4. Save.

Understand what gets sent#

Executing a proxy function sends a POST with a JSON body of this shape:

{
"params": {"order_id": 123, "__method__": "POST"},
"user": {
"id": "USER_ID",
"username": "USER_NAME",
"email": "USER_EMAIL",
"first_name": "FIRST_NAME",
"last_name": "LAST_NAME",
"full_name": "FULL_NAME"
},
"request": {
"method": "POST",
"path": "/api/apps/APP_SLUG/functions/FUNCTION_SLUG/execute/",
"content_type": "application/json"
}
}

params is the caller's input plus __method__, the verb the caller used. user describes the authenticated caller. request holds only the method, path, and content type; the caller's headers and raw body aren't forwarded.

The request always uses POST and always sends JSON, whichever verb the caller used to invoke the function.

Configure authentication#

Four styles are available through auth_config.

TypeFieldsSends
bearertokenAuthorization: Bearer <token>
api_keykey_value, optional key_nameThe key in the named header, X-API-Key by default
basicusername, passwordAn encoded Authorization: Basic header
customheadersEach header exactly as supplied

Add any further headers through the function's headers field.

warning

Credentials in auth_config are stored on the function record, and any organization user with access to the site can read and change that record. Use a credential scoped narrowly to this integration, and rotate it if your organization's members change.

Set the timeout#

Proxy requests time out after 30 seconds. Override that per function through config.timeout, in seconds:

{"config": {"timeout": 10}}

Keep it well below the synchronous execution wait so a caller receives a clear proxy error rather than a stalled request.

Read the response#

A synchronous execute returns the webhook's parsed body in data, without its status code. If the webhook returns an empty body, data is the whole result object described below instead.

The run's full result has the webhook's status_code, its parsed body under response, its headers, and success, which is true for any 2xx status. Read it from the task result, data.result from GET /api/result/TASK_ID/. A non-2xx response is recorded rather than raised, and a redirect is returned as a non-2xx result, not followed. A timeout, connection failure, or unparsable response fails the execution instead.

Point it only at endpoints you trust#

A proxy function forwards to whatever URL it is configured with, so point one only at an endpoint you control or otherwise trust.

Saving checks the URL: it must use https, carry no credentials, and resolve only to public addresses. Loopback, private, link-local, and carrier-grade NAT addresses are rejected, and so are localhost and hosts ending in .local, .internal, or .localhost. Otherwise the save fails with webhook_url must use https or webhook_url host is not allowed. Saving never sends a request, so a wrong path or a failing endpoint still surfaces on the first run.

warning

Anyone who can edit a function in the site can change its webhook_url and auth_config, redirecting the call and its credentials to another destination. Review proxy functions when your organization's members change.

See Security and limits.

Verify#

Execute the function and confirm the webhook received the request and the response came back intact. The invocation record stores the status code and body returned by the webhook, not what the remote system did with the call — check that system's own logs when a result is unexpected.