Skip to content

Respond to a webhook

What it does. Another system calls a web address with ?order=SO-20417. The script finds the documents for that order, reads their Status field, and answers with JSON such as {"order": "SO-20417", "status": "Approved", "documents": 3}. A missing order gets a 404. A call with no order gets a 400.

What you need.

  • The MaSH feature.
  • A webhook on Settings > MaSH > Webhooks: Add webhook, pick the script, set a Username and Password, Save. The URL column shows the address. See Webhooks.
  • Fields on the shares to search: Order No and Status.
  • Remember who the script runs as. It searches what its owner can read. See Who a script runs as.

The caller sends the username and password as HTTP Basic Auth, and the address’s key is a secret too. A call without the right credentials is refused before the script starts.

The reply shape is the part to get right. This block turns “what we found” into a response dictionary. A dictionary with a body key is sent as the whole response, with its status, type and headers:

block reply order statuses
if order is ""
return {"status": 400, "type": "json", "body": {"error": "Give an order number as ?order="}}
end
if count(statuses) is 0
return {"status": 404, "type": "json", "body": {"error": "No order {{order}}"}}
end
return {
"status": 200,
"type": "json",
"body": {"order": order, "status": statuses[0], "documents": count(statuses)}
}
end
print mash.json.encode(reply("", [])["body"])
printline
print mash.json.encode(reply("SO-9", [])["status"])
printline
print mash.json.encode(reply("SO-20417", ["Approved", "Approved", "Draft"])["body"])
printline
{"error":"Give an order number as ?order="}
404
{"order":"SO-20417","status":"Approved","documents":3}
set errorblock to "onError"
block onError
printline "Error on line {{mash.error.line}}: {{mash.error.message}}"
end
block reply order statuses
if order is ""
return {"status": 400, "type": "json", "body": {"error": "Give an order number as ?order="}}
end
if count(statuses) is 0
return {"status": 404, "type": "json", "body": {"error": "No order {{order}}"}}
end
return {
"status": 200,
"type": "json",
"body": {"order": order, "status": statuses[0], "documents": count(statuses)}
}
end
# What the caller sent. A query string or form value is a field on the input.
set order to mash.str(mash.event.input["order"] ?? "").trim().toString()
if order is ""
return reply("", [])
end
set filters to {}
set filters["Order No"] to order
set statuses to []
each mash.fields.findFiles(filters) as hit
set file to mash.files.get(hit["share_id"], hit["path"])
set status to file.fields["Status"] ?? ""
if status is not ""
statuses[] = status
end
end
return reply(order, statuses)
  1. mash.event.input["order"] is the query or form value. Use ["name"] with a fallback, so a missing one is empty and not an error.
  2. A dictionary with body is the response. status sets the HTTP code, type: "json" sends the body as JSON, and headers adds headers. Return anything else (a string, a plain list) and Foldr sends it as the body with status 200.
  3. return reply(...) ends the run with that response. A run that ends in an error sends the caller a 500, with the message in the body. Decide your own status codes instead.
  4. mash.fields.findFiles returns one result per matching file, as name, path and share_id. It searches what the script’s owner may read.
  5. Output you print goes to the run log, not the caller, once a return gives a response.

Never put a secret in the answer unless the caller should have it. The address and the password are the only gate. Treat what the script can read as readable by anyone who can call it.

  1. Save the webhook and copy its URL.
  2. From a terminal: curl -u caller:password "https://<your-address>/hooks/<key>?order=SO-20417".
  3. Open Settings > MaSH > Logs to see the run. Webhook runs also write to the webhook log on the server.

If you can’t get an answer back, check the status code first. 401 means the credentials, 404 means the key, and 500 means the script ended in an error.

  • Take a JSON body. For a POST with JSON, read mash.event.input.foldr_request.content and decode it with mash.json.decode(text, true).
  • Check a signature. Many services sign their calls. Read the header with foldr_request.headers["x-signature"][0], compute the expected value (see the Hash and Crypt pages), and compare. Return 401 when it differs.
  • Do something, then answer. Write a field or queue a script with mash.scripts.queue, then return {"status": 202, "type": "json", "body": {"queued": true}} so the caller isn’t kept waiting. See Running one script from another.
  • Return a page or a file. Return a dictionary with body set to HTML and no type, or return a File to send it as a download. A returned page runs in a browser sandbox. See Webhooks.

Library pages used: Fields, JSON, Request.