POST to it runs the script, with the request body as the trigger’s payload. How the caller proves itself depends on who it is:
Your own code or service
Sign each request with the trigger’s secret.
A service that signs its own webhooks
Stripe, Slack, GitHub and others: pick the provider, paste its secret.
A form on your website
No secret in the page — a reCAPTCHA check and your allowed domains instead.
The contract
- URL:
https://api.script.it/api/webhooks/<token>(your installation’s own API host when self-hosted). The token is minted when the trigger is created and never changes. Turning the trigger off keeps it; deleting the trigger invalidates it. - Request:
POST, with a JSON body or anapplication/x-www-form-urlencodedbody (what a form sends). The body is what your script receives: JSON as sent; a form body as its fields, with a field that appears more than once as a list. - Response:
200with{"inbox_id": "…"}as soon as the request is accepted. The script runs right after, so a slow script never times the sender out. A refused request answers4xxwith{"detail": {"code": "WEBHOOK_INVALID", "reason": "<why>", "message": "…"}}; a429also carriesRetry-After. Each section below lists its reasons.
Signing your requests
Webhook triggers are signed by default: Script.it creates a signing secret with the trigger and checks every request against it, so knowing the URL isn’t enough to run your script. A signed request carries two headers:
The HMAC is computed over the exact body string you send, so sign the serialized body, not an object you serialize again afterwards. A request whose timestamp is more than 5 minutes old is refused, so a captured request can’t be replayed later (
max_timestamp_age_seconds changes the window).
400 with the reason webhook_missing_signature_headers, webhook_invalid_signature, webhook_invalid_timestamp or webhook_timestamp_out_of_range.
Provider-signed webhooks
If the calls come from a service that signs its webhooks its own way, set Provider on the trigger to that service and paste in the secret it gives you. Script.it then checks each request the way that provider signs it, so you point the service straight at your URL with nothing in between. Supported providers: Stripe, Slack, GitHub, Shopify, Zoom, HubSpot, Jira, Trello, Asana, Discord, Zendesk, Intercom, Linear, monday.com, SendGrid, Square, Paddle, Figma, Lemon Squeezy, WhatsApp (and the other Meta webhook products) and Telegram bots.- Verification handshakes (Slack, GitHub, Zoom, Asana, Discord, monday.com, WhatsApp) are answered for you. WhatsApp verifies with a token you paste into Meta’s dashboard; Script.it shows it after you create the trigger.
- Square, Trello and HubSpot sign over the URL as well as the body, so their trigger also needs its own public URL in the Notification URL setting.
- monday.com signs only the webhooks made through a monday app. A webhook made from monday’s UI or API carries no signature, so it needs signature checking off — see Turning signatures off.
If the service is one you’ve already connected to Script.it — Slack, GitHub, Stripe and many more — you usually don’t need a webhook trigger at all. An app event receives the same events with no URL to set up.
Calling it from a web page
A form on your own website — a signup form, a contact form, a request form — can post straight to your webhook. A page can’t keep a signing secret (anyone can read the page’s source), so the form proves itself a different way:- The trigger has Allowed domains set to the site’s domain —
example.comcoverswww.example.comand every other subdomain; several are separated by commas, and a pasted page URL is reduced to its host (https://www.example.com/signup→www.example.com) — and Allow browser requests turned on. Signature checking stays on for everything else that calls the URL. - The page loads reCAPTCHA Enterprise with the site key Script.it gives you (shown with the form in the app, and returned to the agent as
browser_requests_site_key), and each submission sends the form’s fieldsapplication/x-www-form-urlencodedplus one extra field,_captcha_token, holding a token minted for the actionwebhook_submit. - Script.it checks the token, that it was minted on a page served from one of the allowed domains, and that it wasn’t scored as a bot, then removes
_captcha_tokenand runs your script with the remaining fields.
webhook_captcha_required (400, no token in the body), webhook_captcha_rejected (403, the token was invalid, expired or scored as a bot), webhook_captcha_domain_not_allowed (403, the page isn’t on an allowed domain), webhook_browser_rate_limited or webhook_browser_budget_exhausted (429, with Retry-After).
A self-hosted installation decides what a page may do: it can bring its own reCAPTCHA key, allow a form without a captcha for pages that aren’t public (an intranet) on triggers with signature checking off, or allow neither — then the page posts to your own server, which signs the request and forwards it. Where a setting isn’t allowed, the trigger refuses it with a message that names what the installation does allow.
Limiting who can call it
An IP allowlist on the trigger — individual addresses or CIDR ranges — refuses every request from anywhere else withwebhook_ip_not_allowed (403), including a request whose address can’t be determined. It applies on top of signatures and captchas, and it’s the one protection left when signatures are off.
Turning signatures off
You can turn Require signature off when the sender can’t sign its requests — a webhook made from monday’s UI, a tool with no signing option, or a form on a page that isn’t public, on a self-hosted installation that allows it.What your script receives
The request body is the trigger’s payload: a JSON body as sent, a form body as its fields (a repeated field as a list). It reaches your script the way every trigger’s payload does — as a session file, by defaultdata_files/trigger_event.json. See Trigger payloads.
Runs appear in your session history like any other run, and in the trigger’s run history on the script. See Managing triggers.
Settings reference
A webhook trigger’s settings are flat keys. In the app they’re the trigger’s settings; the agent sets them withscriptit trigger create webhook --inputs '{…}' and changes them with scriptit trigger update <trigger_id> --inputs '{…}'.
Managing webhook triggers
- Turn it off and on from the script. The URL is kept, so turning it back on resumes with the same setup.
- Delete it to permanently invalidate the URL. Anything still calling it stops working, and a new trigger gets a different URL.
Setting it up in the app
Creating a webhook trigger
1
Open the Triggers tab
Open the script you want to run, click the Triggers tab, then click Add Trigger.
2
Choose Webhook
Give it a name that says where the calls will come from — “Stripe payment received”, “Deploy finished” — and choose Webhook.
3
Create the trigger
Click Create Trigger. Script.it shows you the webhook URL and the signing secret, with example code for sending a signed request. Copy them — you’ll need them to set up the sending service.
4
Point your service at the URL
Paste the URL into whatever should call it. Most services have a Send test event button — use it, and check that the run shows up on your trigger. For a provider’s own signing, set Provider and Signing secret in the trigger’s settings first.
Adding a web page form
1
Allow your domain
Open the trigger’s settings and enter your site’s domain under Allowed domains.
2
Turn on browser requests
Check Allow browser requests.
3
Paste the form into your page
Open Web page form on the trigger, copy the code, rename the fields to what you want to collect, and paste it into your page.
4
Submit it once
Fill the form in on your live page and check that the run shows up on the trigger.