An agent can do the whole thing.

No SDK, no dashboard, and no screenshots of a UI to guess at. formeasy speaks AgentOnboard, so an assistant signs in with a short-lived token, works on its human’s own forms, and never opens a browser — from signing up to reading the answers.

$ aon token get forms.example.com

POST /api/agent/forms403 ACCOUNT_REQUIRED
POST /api/signup201 created
POST /api/agent/forms201 Team offsite
POST /api/agent/forms/{id}/publish200 /f/8fQ2mVn3k1
GET /api/agent/forms/{id}/responses200 3 answers

There is almost nothing to learn.

A form here is two tables and a handful of routes. That is a taste in interfaces, but it is also the property that makes the product usable by a program that has never seen it: nothing to install, no graph to walk, no widget to click, no UI state to infer from a page it cannot render.

Every surface an agent needs is an HTTP request with a JSON body and a stable error code when it goes wrong. Minimalism is not only how this looks. It is why the integration is an afternoon, not a project.

One switch turns it on.
AON_AUDIENCE set to the deployment's hostname, and agent access exists. Unset, it is off: /auth.md answers 404 rather than advertising a capability the deployment does not have, and every agent route fails closed.
Discovery is a file, not a wiki.
/auth.md is rendered from the same value the token check uses, so the audience an agent is told to mint for cannot disagree with the audience we verify. One request, and the agent knows every endpoint and what each rejection means.
The same account, not a shadow one.
An agent works on its human's own forms — reading, editing, publishing, exporting. A write lands under the user id the token resolved to, never a value from the body and never a path parameter.
Errors are sentences with codes.
One body shape throughout: { code, error }. 401 means re-mint the token once. 403 ACCOUNT_REQUIRED means sign up, then retry once. 500 means our side failed; the token is fine. Nothing to guess at.

Sign in, sign up, get it done.

  1. 01

    Sign in.

    Mint a short-lived token for the audience the deployment publishes, and send it on every request. No password, no session cookie, no browser. The token lives five minutes; the agent mints another rather than hoarding one.

    # the audience comes from the deployment's own /auth.md
    aon token get forms.example.com
    
    # then, on every request:
    #   Authorization: Bearer <token>
  2. 02

    Get told to sign up.

    An identity with no formeasy account is not an error to retry around — it is an instruction. The first call answers 403 ACCOUNT_REQUIRED, the agent posts the same token to /api/signup, and retries its original request once. The same address twice signs in instead of duplicating.

    curl -sX POST https://forms.example.com/api/signup \
      -H "Authorization: Bearer $TOKEN"
    
    # 201 {"user":"user_2x…","created":true}
  3. 03

    Do the work.

    Create, edit, publish, read the answers, download the CSV. Every one of them is a JSON request against the same account the person sees in the dashboard, and every one of them returns the same objects the app renders.

    curl -sX POST https://forms.example.com/api/agent/forms \
      -H "Authorization: Bearer $TOKEN" \
      -d '{"title":"Team offsite"}'
    
    # 201 {"id":"8fQ2mVn3k1","status":"draft","publicPath":"/f/8fQ2mVn3k1"}
    
    curl -sX POST https://forms.example.com/api/agent/forms/8fQ2mVn3k1/publish \
      -H "Authorization: Bearer $TOKEN"
    
    # 200 published — or 400 INVALID_FORM, carrying the problems to fix

What it deliberately will not do.

Handing a program the keys to an account is a decision worth stating out loud, so here are the boundaries. The whole endpoint list, with the rejection table, is in the deployment’s own /auth.md.

Anyone who can receive mail can make an account.
That is what "agents can sign up" means, and on a public deployment it is a deliberate choice rather than an oversight. Leave AON_AUDIENCE unset and the whole surface is gone.
The audience is configuration, never the request's Host.
A token minted for another service is refused, not obeyed. Deriving the audience from the request would turn a check into an instruction — the same reasoning that keeps a link preview's host out of the metadata.
It cannot reach an account it was not verified for.
There is no query parameter for "whose forms". The owner is the account the verified email resolved to, so one agent cannot read or write another person's answers.
Publishing still validates.
An agent gets no back door: publish runs the same rules the app's own publish button runs, and a form that is not ready comes back with a list of sentences to fix.

Point an agent at it.

Turn on the audience, hand over a token, and the rest is HTTP.