Calling your URL
The signed request your own code receives, and external tools.
Your own code runs on your host, and call_url is how a relay reaches it.
Gemmein POSTs one JSON body:
{
"id": "…", // the event id, the same on every retry and replay
"relay": { "id": "…", "name": "gocardless-paid" },
"trigger": "receiver", // receiver | schedule | data_change | credits_low | run_started
"event": { … }, // the stored payload: { event, mapped } | { record, previous } | { tick }
"person": { "id": "…", "email": "…" }, // or null
"results": [ … ] // the actions that ran before this one
}
The request carries content-type: application/json,
user-agent: Gemmein-Relays/1 and
X-Gemmein-Signature: t=<unix seconds>,v1=<hex>, where
v1 is the HMAC-SHA256 of the timestamp, a dot, then the body, with the
relay's signing secret. That secret is shown once when the relay is created and can be
rotated. Verify over the raw body, in constant time, before trusting anything:
import { createHmac, timingSafeEqual } from "node:crypto"
const [t, v1] = req.headers["x-gemmein-signature"].split(",").map(p => p.slice(p.indexOf("=") + 1))
const expected = createHmac("sha256", process.env.GEMMEIN_SIGNING_SECRET).update(`${t}.${rawBody}`).digest("hex")
const ok = expected.length === v1.length && timingSafeEqual(Buffer.from(expected), Buffer.from(v1))
A 2xx answer is done. A redirect is a failure and is never followed. The call times out after ten seconds. The status and the first 4 KB of the answer are kept on the event, so you can read what your URL said.
Your URL must deduplicate on id. The
call is not idempotent on Gemmein's side: a replay, a retry after the relay was edited,
and a call cut off by a deploy POST the same id again. Keep the ids you have handled. The whole event is in the body, so the URL
receives private data; it is your host, over https.
Refused addresses arrive as the action's error, naming the rule:
https_only, ip_literal, own_host,
unresolvable, private_address. Gemmein calls public addresses
only, checks the address on every attempt, and pins the connection to the address it
checked.
External tools
A tool whose provider is external does not use a relay: starting a run
POSTs it straight to the tool's own URL, signed and retried, with no relay event. The
request body, the /complete, /fail and /progress
endpoints and the g.pipelines.handle helper are on
Your own pipeline.
Thanks for telling us.
Thanks for telling us.
Last updated