Build
Incoming webhooks
A webhook trigger gives the workflow a private address. Your system POSTs JSON to it with a secret, Filmo answers 202 straight away, and a run starts.
Set it up
Link to this section: Set it up- Choose «Webhook» as the trigger. Under «Body», declare the type of the JSON you will send.
- In the trigger's side panel you will find «Endpoint» and «Secret», each with a copy button. They are shown in clear text, and they exist from the moment the workflow is created.
- Publish the workflow and switch it «Live». The address answers 404 until then, and answers 404 again if the workflow is paused or the trigger is changed to another type.
The request
Link to this section: The requestcurl -sS -X POST "https://app.filmo.io/api/webhooks/workflows/whk_<token>" \
-H "X-Webhook-Secret: whsec_<secret>" \
-H "Idempotency-Key: order-2026-0042-reserved" \
-H "Content-Type: application/json" \
-d '{"orderNumber":"P-2026-0042","customerEmail":"ana@example.com"}'- Only POST is accepted. The token is part of the address (
whk_followed by random characters), and the secret (whsec_…) goes in the headerX-Webhook-Secretor asAuthorization: Bearer <secret>. If both are present,X-Webhook-Secretis used. The secret is required on every call. It is a shared secret, compared in constant time; it is not a signature of the body, so a captured request can be replayed. - The body is parsed as JSON whatever the
Content-Typesays. Send a JSON object (a list or a text also work). - The body can be at most 256 KiB.
- The address of the workflow in your Filmo app is the host of that app followed by
/apiand the token./webhooks /workflows/
Responses
Link to this section: Responses| Status | Body | When |
|---|---|---|
| 202 | { "runId": "…" } | A run was queued. |
| 200 | { "runId": "…", "duplicate": true } | You repeated an Idempotency-Key already seen on this workflow: no new run, the id of the existing one. |
| 400 | { "error": "invalid_json" } | The body is empty or is not JSON. |
| 400 | { "error": "idempotency_key_too_long" } | The key is longer than 255 characters. It is refused, not truncated. |
| 401 | { "error": "unauthorized" } | The secret is missing or wrong. |
| 404 | { "error": "not_found" } | Unknown token, the trigger is not a webhook, the workflow is not live, or it is paused. They are all the same answer on purpose. |
| 409 | { "error": "no_version" } | The workflow has never been published. |
| 409 | { "error": "conflict" } | A rare race with a duplicate whose run has disappeared. |
| 413 | { "error": "body_too_large" } | Over 256 KiB. |
| 429 | A message and retryAfterMs, with a Retry-After header | More than about 60 requests in a minute to this address. The count is kept per server instance, so it is approximate. |
Any other method answers 405.
The body is checked after the 202
Link to this section: The body is checked after the 202A 202 does not mean the body was valid
Filmo checks the body against the type you declared when the run starts, not when the request arrives. If the body does not match, you have already received 202 and the run fails with a message such as "the webhook body does not match the declared type: …". The sender never finds out. Open the run in the «Runs» to see why.
The rules: extra fields are ignored; every field you declared is required (declare a field as Unknown to accept anything); a number must be a JSON number, not a text; a date must be ISO 8601; an enumeration must be one of its options. The variable trigger_body holds the body as you sent it, including the fields you did not declare.
Don't start the same run twice
Link to this section: Don't start the same run twice- Send an
Idempotency-Keythat identifies the thing that happened (an order number and what happened to it), not the attempt. A redelivery with the same key returns 200 and the original run. The key is unique per workflow, not across workflows. - Without the header, nothing is deduplicated: two identical deliveries start two runs, because two identical bodies can be two real events. Filmo never uses the body to decide.
- The protection lasts as long as the run exists. Finished runs are deleted 90 days after they end.
The credentials
Link to this section: The credentials- The token and the secret are created with the workflow, for every workflow, even if it never uses a webhook. They do not belong to a version: they do not change when you save, publish, change the trigger or restore anything.
- There is no way to rotate or regenerate them. If a secret leaks, the remedy is to build a new workflow, which gets new credentials.
- They are shown to everyone who can open the workflow in the editor. For a «Public» workflow that means any member of your company. If that is not what you want, switch the workflow to «Private»: only its creator and administrators can then open it.
What runs, and as whom
Link to this section: What runs, and as whomThe run starts with the published version, executes with the permissions of the workflow's creator, and sees the body in trigger_body. Delivery is at least once for the effects of its steps: see Errors and retries.
To see it end to end, the guide Start a workflow from your own system sets up a webhook, a type and a test delivery.
Related pages
Link to this section: Related pagesBuild
Triggers
A trigger decides when a workflow runs. Every workflow has exactly one, and you can change it in the editor at any time (until you publish, nothing changes for the runs).
Build
HTTP requests
The HTTP step calls a URL from a run: to push a change to your own system, or to read from one. It is deliberately simple, and the simplicity has consequences you should know before you build on it.
Run
Workflow permissions
Two questions get mixed up: who may manage a workflow, and what a run is allowed to do. The first is about administrators. The second is about one person: the creator.
Was this page helpful?