What you will take away from this lesson
An automation runs on demand, on a schedule, once per event, or once per request. The 600 series covered the first three. This series covers the fourth: another system calls an address, and the automation answers it. A store finder on a website, a partner’s replenishment system checking stock, a dashboard in another tool pulling a feed. Each is an endpoint.
This lesson builds the simplest one on the demo tenant, a public store finder, and uses it to show the parts every endpoint shares: the handler, the binding, the limits, and the answers a caller can get.
Learning Objectives
- 01Say what an endpoint is, and what it is not: a lookup or feed another system calls, never a web application.
- 02Read the request a handler is handed and write the answer it returns.
- 03Name who binds an automation to an endpoint and the settings a binding holds.
- 04State the limits one request runs under and what a caller is told when it fails.
- 05Draft and test a handler the way any automation is drafted and tested.
Where this lesson sits
The 700 series starts from the automations of the 600 series. An endpoint is an automation that runs once per request, and a form is an endpoint people fill in.
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.
What an endpoint is
An endpoint answers a request from another system with data the platform holds, under the same governance as every other automation.
What an endpoint is
An automation
- An endpoint is a managed script like any in the 600 series: written by the agent, saved with tests, versioned, and run under the access its author held at the save. What makes it an endpoint is one function, handle(req), and a binding to an address.
An address
/endpoints/<name>
- Each binding has a name unique across the deployment. A request to that address runs the handler on the server that received it and answers with what the handler returns.
A lookup or feed
- The answer is data: JSON computed from the warehouse, the catalog, an API connection, or anything else the automation may reach. Every answer is served as an opaque document that runs no script, and is not cached unless the handler says so.
Not web hosting
- An endpoint does not serve a website or an application. It answers requests with data, one at a time, inside fixed limits. A page people fill in is a form, the subject of 703.
A request writes no run to the automation’s run history. It writes one audit row of its own, and every platform call the handler makes is audited under the automation’s name, as a scheduled run’s calls are. Lesson 702 reads those rows.
The request a handler is handed
The platform hands the handler one dictionary per request. The caller’s credentials are never in it; the platform has already decided who the caller is.
What handle(req) is handed
method
- The HTTP method: GET, POST, PUT, PATCH, DELETE, or HEAD.
path
- The path the caller sent.
params
- Values from the binding’s path template. A template of /{sku} hands the segment over as params["sku"].
query
- The first value of each query parameter, such as query["state"].
headers
- The request headers with names in lower case. The caller’s credentials (Authorization, Cookie, X-API-Key) are left out.
body, json, form
- The body as bytes, parsed as JSON when it says it is JSON, and as fields when it is a URL-encoded form. A body that claims to be JSON and is not is refused before the handler runs.
caller
- Who the platform found the caller to be, on an endpoint that requires sign-in or a key: their id, email, and whether they used a session or an API key. It never comes from the request body. Lesson 702 covers the access modes.
The handler returns a status (200 unless it says otherwise), optional headers, and either json or a body. It may not set cookies or the headers that control framing, scripts, or cross-origin access; the platform sets those on every answer.
The store finder
Asked for a store finder the ACME website could call, the agent wrote a handler that answers every active store in one state.
acme-store-finder, the handler
def handle(req):
"""Lists the active ACME stores in one state, for the store finder on acme.example.com."""
state = req["query"].get("state", "").upper()
if state not in STATES:
return {"status": 400, "json": {"error": "state must be a two-letter US state code"}}
rows = platform.query(
"SELECT s.store_id, s.store_name, s.address, s.city, s.state, s.zip_code, s.phone, " +
"r.region_name AS region FROM warehouse.public.stores s " +
"JOIN warehouse.public.regions r ON r.region_id = s.region_id " +
"WHERE s.is_active AND s.state = :state ORDER BY s.city, s.store_id",
params = {"state": state},
connection = "acme",
)
return {
"headers": {"Cache-Control": "public, max-age=300"},
"json": {"state": state, "count": len(rows["rows"]), "stores": rows["rows"]},
}The automation the agent saved on the demo tenant, less its list of state codes and its tests. The state is checked against a fixed list before it reaches SQL, the query binds it as a parameter, and the answer allows a five-minute cache because the store list changes rarely. Nothing else about the warehouse is reachable through the address.
Putting it at an address
A saved automation answers nothing until it is bound. The binding names the address, the methods, who may call, and the limits.
Binding the store finder
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": "endpoint_set",
"name": "acme-store-finder",
"endpoint": "store-finder",
"methods": ["GET"],
"auth_mode": "bot_check",
"bot_check": "default",
"allowed_origins": ["https://www.example.com"],
"rate_limit": 300,
"timeout_seconds": 10
}
← {
"endpoint": "store-finder",
"enabled": true,
"url": "https://mcp-demo.plexara.io/endpoints/store-finder",
"max_body_bytes": 1048576,
"max_memory_bytes": 67108864,
"caller_rate_limit": 120,
"message": "acme-store-finder now answers GET at
https://mcp-demo.plexara.io/endpoints/store-finder."
}Binding is an administrator’s action. The automation’s owner cannot bind it, so an address that answers the outside world exists because an administrator on your team decided it should. An administrator can do the same on the automation’s page in the portal, in its Endpoint section, and turn the endpoint off there without touching the automation; a turned-off endpoint answers 404.
A binding is refused for a script with no handle, and a later save that removes it is refused too, naming the endpoint.

What a binding holds
Every setting has a standard value except the name and the access mode, which an administrator always chooses.
What a binding holds
endpoint
- The name in the address. Lowercase letters, digits, hyphens, and underscores, unique across the deployment.
methods, path
- The methods answered (GET unless set) and an optional template under the name, such as /{sku}.
auth_mode
- Who may call: authenticated, public, or bot_check. Required, with no default. Lesson 702.
timeout_seconds
10, at most 60
- How long one request may run before the caller is answered 504.
max_body_bytes
1 MiB, at most 10 MiB
- The largest body accepted. A larger one is answered 413 and the handler never runs.
rate_limit
600 a minute
- Requests a minute the endpoint takes on each server. Past it, a caller is answered 429 with a time to retry.
allowed_origins
- Websites whose browsers may call the endpoint directly from a page. Empty answers no cross-origin request.
One request
The store finder page on the website sends the state a visitor picked and renders the stores it gets back.
One request to the store finder
What the calling system sends. This is the HTTP exchange the store finder page on the ACME website has with the endpoint, shown for the technical reader. The calling system sends it on its own; nobody types it.
GET /endpoints/store-finder?state=il
X-Bot-Check: <the answer to the store finder's challenge>
200 OK
Cache-Control: public, max-age=300
Content-Security-Policy: default-src 'none'; sandbox
{
"state": "IL",
"count": 12,
"stores": [
{ "store_id": 103, "store_name": "ACME Store #103", "address": "1202 Park Dr",
"city": "Arlington", "state": "IL", "zip_code": "96952",
"phone": "(926) 696-6809", "region": "Midwest" },
{ "store_id": 96, "store_name": "ACME Store #96", "address": "5141 Main Rd",
"city": "Ashland", "state": "IL", "zip_code": "45629",
"phone": "(965) 820-6941", "region": "Midwest" },
... ten more
]
}The page fetched a proof-of-work challenge, solved it in a fraction of a second, and sent the answer with the request. Lesson 704 covers bot checks. The handler answered in the time it took to run one query.
What a caller is told
Some answers come from the handler and the rest from the platform, before or after the handler runs.
What a caller is told
400
from the handler
- Whatever the handler decides. The store finder answers 400 with a message for an unknown state.
404
- No enabled endpoint has the name, or the path does not match the template.
405
- The method is not one the endpoint answers; the answer lists the ones it does.
413
- The body is larger than the binding allows. The handler does not run.
429
- Past the endpoint’s rate, or the caller’s own rate on an authenticated endpoint, with a time to retry.
500
- The handler failed, or returned something that is not an answer.
503
- The automation is disabled or superseded, the handler held too much memory, or the server is already running its share of handlers.
504
- The handler ran past its timeout.
A caller learns which of these it got and never the automation’s error. The error is kept for seven days with the request’s status and duration, listed on the automation’s page, where the owner reads it.
Limits
Each request runs inside fixed limits, so one slow or greedy caller cannot hold the platform up for the rest.
The limits one request runs under
- default time per request, at most 60
- 10 s
- memory one request may hold
- 64 MiB
- default body, at most 10 MiB
- 1 MiB
- handlers running at once on each server
- 32
Rate limits count on each server, and no limit depends on the caller’s network address. A handler cannot write an output or refresh a dashboard: a request answers with what handle returns, and work that should leave something behind belongs to a run, started by a schedule or by an event.
Drafting and testing a handler
A handler is written the way every automation is written: drafted for real, tested against a recording, and saved only when the tests pass.
Drafting and testing a handler
- 1
Draft with a request built by hand
A draft runs main(), so the agent writes a main() that calls handle with the request a caller would send. The draft runs for real and records every platform call and its answer.
- 2
Test against the recording
A test replays that recording and asserts on the answer: the store finder’s tests check that Illinois returns 12 stores in the Midwest and that ZZ is answered 400.
- 3
Save, and the tests run
A save runs the tests as it does for any automation and is refused while one fails or a branch is never reached.
- 4
Every request runs the newest version
The first request after a save runs the new version on every server. There is no separate deploy step.
The loop is the one lesson 602 taught. The agent writes the handler, runs the draft, writes the tests, and saves; an administrator binds it once it is right.
Who may call
Key terms
Four terms cover what an endpoint is and how it is put at an address.
Key Terms
- Endpoint
- An automation bound to an address of its own that answers each request with data. A lookup or feed another system calls.
- Handler
- The handle(req) function the platform calls with each request. Its return value is the answer.
- Binding
- The settings that put an automation at an address: name, methods, path, access mode, limits, and allowed origins. Set by an administrator.
- Access mode
- Who may call an endpoint: authenticated callers, anyone, or anyone who passes a named bot check.
