What you will take away from this lesson
A table of applications is only useful if somebody looks at it. The vendor team wants to hear about each application as it arrives, with the facts that decide whether to call back: which category, how much of it ACME already carries, which store the supplier wants to start at, and who manages it.
Each accepted submission is an event in the form’s source, the same kind of source the 600 series read webhooks from. An automation can name that source and run once for each event it stores.
Learning Objectives
- 01Run an automation once for every submission a form stores.
- 02Read a submission from run.event and act on it under the automation’s own access.
- 03Refuse a submission against live data before it is stored, field by field.
- 04Say what happens on a burst of submissions and on a failed run.
- 05Decide whether work belongs in form_submit or in the run that follows.
Where this lesson sits
Lessons 703 to 705 built the supplier form, published it, and protected its tax ID. This lesson acts on what it collects.
700 Series: Endpoints and Forms
- 701An automation that answers a requestWhat an endpoint is, the request a handler is handed and the answer it returns, who binds it, the limits a request runs under, and what a caller is told.
- 702A lookup a partner system callsThe three access modes, API keys and per-caller limits, one audit row per request, refusals by reason, signed tokens, and the Endpoints page.
- 703Your first formA form the agent writes: fields, live choices, field-by-field refusals, the checks the platform runs first, the hosted page, and submissions as a table.
- 704Putting the form on your site, or in a reportEmbedding in an asset and on an allowed site, named bot checks, the honeypot, and the minimum fill time.
- 705Sensitive fieldsEncryption before storage, who reads in clear and where, audited reads, exports, and why a file field cannot be sensitive.
- 706From submission to actionAn automation that runs once per submission, validation against live data, bursts and failures, and writes to other systems.
- 707Capstone: the supplier form end to endThe demo tenant’s supplier program assembled: form, page, table, intake automation, and a report joining applications to the warehouse.
The 700 series builds on the automations of the 600 series: an endpoint is an automation that answers a request, and a form is an endpoint that people fill in.
The intake automation
The agent wrote an automation that takes one application, adds what the warehouse knows, and tells the vendor team.
acme-supplier-intake (body shortened)
def intake(event):
"""Checks one supplier application against the warehouse and posts it to the operations feed."""
values = event["payload"]["values"]
store = platform.query(
"SELECT s.store_name, s.city, s.state, s.manager_name, r.region_name FROM warehouse.public.stores s " +
"JOIN warehouse.public.regions r ON r.region_id = s.region_id WHERE s.store_id = :id",
params = {"id": int(values["pilot_store"])}, connection = "acme",
)["rows"][0]
category = platform.query(
"SELECT c.category_name, count(p.product_id) AS products FROM warehouse.public.categories c " +
"LEFT JOIN warehouse.public.products p ON p.category_id = c.category_id " +
"WHERE c.category_id = :id GROUP BY c.category_name",
params = {"id": int(values["category"])}, connection = "acme",
)["rows"][0]
platform.notify(
channel = "ops-events",
title = "Supplier application: " + values["company_name"],
body = ..., # company, category and products carried, contact, pilot store and manager,
# volume, first delivery, files attached, "Tax ID: received, encrypted"
data = {"kind": "supplier_application", "event_id": event["id"], ...},
)
def main():
"""Handles the supplier application this event run was made for."""
if run.event == None:
fail("acme-supplier-intake runs once per stored application; start it by submitting the supplier-onboarding form")
platform.result(intake(run.event))The automation reads the submission from run.event, looks the pilot store and the category up in the warehouse, and posts a summary to the operations feed with a structured payload a system can route on. It never decrypts the tax ID. Started any other way, it fails with a message saying how it is meant to run.
Running it once per submission
The automation runs for the form’s source once it names it.
Naming the form’s source
What the agent calls. This is the exchange the agent has with Plexara on your behalf, shown for the technical reader. You ask in plain language; you never type any of it.
→ manage_script
{ "command": "update", "name": "acme-supplier-intake",
"event_source": "form-supplier-onboarding", "exclusive": "queue" }
← { "status": "updated", "version": 1,
"message": "Saved, and this version is what runs now ..." }The same setting is on the automation’s page in the portal, under Events, beside the schedule. The owner of a form may name that form’s source; an administrator may name any source. Setting it to queue makes runs one at a time, in the order submissions arrived.
What a run reads
An event run is handed the stored submission. Every other run has no event.
What run.event holds
id
- The stored event’s id, the one the run is made once for.
type, key
- form_submission, and the submitter’s address on a form that requires sign-in.
received_at
- When the source received it.
source
- form-supplier-onboarding.
payload
- The submission: values (sensitive ones as ciphertext, files described), the fields in order, and the submitter.

One application, one run
Northfield Paper Goods applied to supply paper products with a pilot at a store in Texas. This is the run its application made.
One application, one run
What the agent calls. This is the exchange the agent has with Plexara on your behalf, shown for the technical reader. You ask in plain language; you never type any of it.
→ manage_script get_run acme-supplier-intake
← { "trigger": "event",
"event_source": "form-supplier-onboarding",
"event_id": "345829bdb1f4a944cf0d3eff46783698",
"status": "succeeded", "duration_ms": 431, "queries": 2,
"result": { "company": "Northfield Paper Goods",
"category": "Paper Products", "region": "Southwest" },
"log": "notify: send to ops-events: accepted for delivery" }
what the operations feed received
title Supplier application: Northfield Paper Goods
body **Northfield Paper Goods** applied to supply **Paper Products**
(207 products in the category today).
- Contact: Grace Okafor, [email protected]
- Pilot store: ACME Store #254, Fairview, TX (Southwest; manager Elizabeth Garcia)
- Expected annual volume: $350000
- Certificate of insurance: 1 file attached
- Tax ID: received, encrypted
link the run's page in the portalThe run started seconds after the submission was stored and took under half a second. The post links back to the run, so whoever reads it can open what produced it. On the demo tenant the feed is a webhook channel received by a source of its own; a team would point the same post at a Slack or Mattermost channel or an email list.
The Events section
The automation’s page counts what its source has handed it and what is waiting.
The intake automation’s Events section
- applications stored, 37 event runs
- 37
- runs failed
- 0
- pending in the queue
- 0
- pending runs the queue holds before skipping
- 100

What an event run guarantees
A form that collects applications needs every one acted on once, even when a burst arrives or a run fails.
What an event run guarantees
- 1
One event, one run
A run is made once per automation, source, and event id. A second server noticing the same submission makes no second run.
- 2
Never inside the person’s request
The run is queued when the submission is stored and executes afterward, so a slow or failing automation never slows the form or loses a submission.
- 3
A failure alerts and is not replayed
A failed run is recorded with its cause and its owner is told. The platform does not run it again on its own, and the next submission still runs.
- 4
A burst is bounded
An automation holds at most 100 pending event runs. A submission past that is recorded as skipped, with a reason saying it is still in the source, and the Events section counts skips for seven days.
- 5
One at a time when asked
An automation set to run one at a time runs its event runs in the order they arrived; an event run waits rather than being refused.
These are the rules lesson 607 described for sources other systems post to. A form’s source is one more source.
Refusing against live data
Some checks need data, and they belong before the submission is stored, where the person can still correct it.
Version 2 of the form: checked against the stored applications
def already_applied(company):
"""Reports whether an application from this company is already stored."""
rows = platform.query(
"SELECT count(*) AS n FROM scratch.uploads.webhook_form_supplier_onboarding " +
"WHERE lower(trim(json_extract_scalar(payload, '$.values.company_name'))) = lower(trim(:company))",
params = {"company": company}, connection = "acme",
)
return rows["rows"][0]["n"] > 0
def form_submit(req, values):
errors = {}
...
if already_applied(values["company_name"]):
errors["company_name"] = "An application from this company is already with the vendor team. " +
"Reply to its confirmation instead of applying again."
if errors:
return {"errors": errors}
return NoneThe vendor team asked for repeat applications to be turned away. The agent added a query to form_submit, and because that changes what the form does, the save waited for the owner to agree to a plain-language summary of the change. Its tests replay a draft that tried a new company, a malformed tax ID, and a repeat with different capitals and spaces.
On the demo tenant a second application from Lakeshore Pantry Co. was answered 422 with that message on the Company name field. Nothing was stored and no run was made.
Where the work belongs
The supplier program now has work on both sides of the store: a check before it and an action after.
Where the work belongs
form_submit
before storing
- Checks that decide whether the submission is acceptable at all, answered to the person on the page: a malformed value, a repeat, a store that is not taking suppliers. Keep them quick; the person is waiting.
the event run
after storing
- Everything that acts on an accepted submission: a post to a channel, a lookup that enriches it, a write to the CRM or the ERP through an API connection. A slow or unavailable system delays the run, never the person.
A write to another system from the event run goes through an API connection that holds the credential, so the automation never sees it, and the call is audited under the automation’s name like every other call it makes.
Next: the capstone
Key terms
Three terms cover how an automation runs for each submission.
Key Terms
- Event run
- A run made once for one event a source stores, reading it as run.event, under the automation’s saved access.
- Event source
- The source an automation runs for. A form’s source is form-<endpoint>.
- Skipped backlog
- The record of an event past an automation’s queue of 100 pending runs. The event stays in its source.
