Call your scripts and flows
An app calls the same endpoints any other system calls: publish a script or flow, turn on its endpoint, and the page sends its form to /exec/<project>/<path>.
- Call an endpoint from a page with the helper or with fetch
- Read the request in a script that declares request
- Know why a downloaded copy keeps working
A form that runs a flow
Publish the flow that records a confirmation and turn on its endpoint with the path rsvp and Public access. Then, in the app:
<form id="rsvp">
<input name="name" placeholder="Your name" required>
<button>Confirm</button>
</form>
<p id="done" hidden>See you there!</p>
<script src="/_waiso.js"></script>
<script>
document.querySelector('#rsvp').addEventListener('submit', async (e) => {
e.preventDefault()
const name = new FormData(e.target).get('name')
await waiso.call('rsvp', { name }) // POST /exec/<project>/rsvp
document.querySelector('#done').hidden = false
})
</script>/_waiso.js is served on every app address. It knows the app’s project and the platform’s address, so waiso.call(path, body) is all a page needs; it answers the run’s output (or throws with the refusal).
Without the helper
// Without the helper: the endpoint's address, as any caller uses it.
const res = await fetch('https://waiso.dev/exec/p_1a2b3c/rsvp', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Ana' }),
})
const { output } = await res.json()The project part of the address is its public id (shown on the API page), never its name. The answer is the same JSON any caller gets: output holds what the script or flow returned, status says how the run ended, and a refusal carries a code such as invalid_args when a required field is missing.
Prefer sync endpoints for anything a visitor waits for — the answer comes back in the same call. For long work, an async endpoint answers a runId at once and the page can poll it.
What the script receives
The form’s fields arrive as the script’s parameters, as in any call. A script that also declares a request parameter receives the call itself — method, path, query, headers and body — with credentials masked:
def main(name: str, request: dict):
# request = {method, path, query, headers, body} as the call arrived
origin = request["headers"].get("origin", "")
return {"saved": name, "from": origin}A flow gets the same object through a preprocessor step, as with any endpoint. Use it to read a query string, a header your page sets, or the origin the call came from — never to trust who the visitor is; for that, see the login below.
A copy hosted elsewhere
Endpoints answer any address, so the zip you Download works on any host: the helper keeps calling this project, and nothing in the page points at waisoapps.app.
1<h1>Bruna & Talisson</h1>2<form id="rsvp">3 <input name="name" placeholder="Seu nome">4 <button>Confirmar presença</button>5</form>6<script src="/_waiso.js"></script>This is also why there is nothing special to learn: an app is a page, the work is a script or a flow, and the bridge between them is the same endpoint you would give a partner system or a spreadsheet. Change the flow and every page that calls it gets the new behaviour on the next call, without publishing the app again.
Keep it in check
- A public endpoint can be called by anyone who reads the page: give it a calls per minute limit on the API page.
- Each call is a run of your plan, like any other call.
- For pages only some people should use, see Login by a flow.