Skip to main content

Create a Webhook

A webhook lets something on the internet start your flow — a form provider, a payment gateway, GitHub, another system. Two nodes do it: Http In receives the request, Http Out answers it.

You no longer need a public address

This used to be the hard part: a robot behind a firewall had no address the outside world could reach, so a webhook meant port forwarding, a static IP or a tunnel you ran yourself.

It does not any more. Http In always publishes a managed public URL:

https://webhooks.robomotion.io/<flow-id>/<your-endpoint>

The robot opens an outbound tunnel and Robomotion routes requests down it. No inbound firewall rule, no port forwarding, no certificate to manage — the URL is HTTPS already.

The Webhook URL property on the node is read-only and shows you the exact address. Copy it and paste it into whatever needs to call you.

Several Http In nodes, one tunnel

Multiple Http In nodes in the same flow share a single connection, distinguished by their endpoint paths. Adding a second endpoint costs nothing.

The flow

A webhook flow: receive, validate, branch, respond

Read it left to right: the request arrives, the flow checks it, does the work or refuses, and sends one response either way.

Http In

Property
Webhook URLRead-only. The public address to hand out
MethodGET, POST, PUT, DELETE, PATCH — and you may select more than one
EndpointThe path this node answers on, e.g. /tickets. Must start with /
IP (Local) and Port (Local)Optional. Also bind a local listener, default 127.0.0.1:9090

What arrives on the message

Field
msg.bodyThe request body — parsed JSON if it is valid JSON, otherwise the raw string
msg.headersRequest headers, names lowercased
msg.cookiesRequest cookies, names lowercased
msg.queryParamsEverything after the ?
msg.pathParamsNamed parts of the path — see below

Path parameters

An endpoint can capture parts of its own path:

/tickets/:id

A request to /tickets/4271 puts 4271 in msg.pathParams.id. That is how you build a real route rather than passing everything as query strings.

Http Out

Every request needs an answer. Http Out is a terminal node — wire into it, nothing comes out.

PropertyDefault
Status Code200Any valid code, 100–599
Bodymsg.bodyString or object; objects are serialised as JSON
Custom HeadersContent-Type: application/jsonSet on new nodes
Cookiesmsg.cookiesCookies to set on the response
Attachment Pathmsg.attachmentA file on the robot to return as a download. Overrides the body

The attachment is worth knowing about: point it at a path on the robot and the webhook returns that file. A flow can generate a PDF and hand it straight back to the caller.

Every path needs an Http Out

The caller is waiting. A branch that finishes without reaching an Http Out leaves the request hanging until it times out — and the sender usually retries, which runs your flow again.

In the flow above, both the success and failure branches converge on the same Http Out. That is the pattern to copy.

Answer quickly, work afterwards

Most providers expect a response in a few seconds and will retry if they do not get one. If the work takes longer than that, do not make the caller wait:

  1. Http In receives it
  2. Validate just enough to know the request is well formed
  3. Put the payload in a queue
  4. Http Out answers 202 immediately
  5. A separate flow, started by a Queue trigger, does the real work

That is exactly how Robomotion's own HTTP triggers are built, and it is the difference between a webhook that survives a busy morning and one that times out under load.

Securing it

The URL is public. Anyone who learns it can call it, so the flow has to decide whether it should.

Check a shared secret. Have the caller send a header — X-Webhook-Token — and compare it in a Function node against a value from a vault. Reject with 401 if it does not match.

Verify a signature if the provider offers one. GitHub, Stripe and others sign the body with a secret you both know; that is stronger than a static token because it also proves the body was not altered.

Validate before acting. msg.body is whatever was sent, including nothing at all. The example flow checks for a required field and answers 400 rather than letting a Function throw on undefined.

Do not trust the payload

A webhook is an unauthenticated endpoint on the public internet until you make it otherwise. Treat everything on msg.body as hostile input.

Testing it

Copy the Webhook URL off the node and call it:

curl -X POST https://webhooks.robomotion.io/<flow-id>/tickets \
-H "Content-Type: application/json" \
-d '{"subject":"Printer is on fire"}'

The flow must be running for the URL to answer — the tunnel exists only while a robot is running the flow. During development that means pressing play; in production it means a published flow on a connected robot.

On-prem: turning the public URL off

Sites that must not expose anything publicly can disable the tunnel entirely by setting

core.net.httpin.webhooks=false

in the robot's config.properties. Http In then serves only the local IP and port, and no public URL is published. Everything else on this page still applies — you just supply the routing yourself.

See also

  • HTTP Trigger — the managed alternative, queue-backed
  • Calling an API — making requests instead of receiving them
  • Queues — the buffer behind a fast response