Skip to Content
ReferenceThe /veris/* control plane

The /veris/* control plane

Every twin serves the same set of routes for reading and changing its world.

Every twin serves two things: a vendor API, which your code calls, and a control plane at /veris/*, which your agent calls.

Both are on the URLs veris sandbox services get prints. url is what your code points at. control_url is where /veris/* lives. For an HTTP twin they are the same. For a Postgres twin url is a connection string and control_url is still HTTP.

No API key is needed. Anyone holding the control_url can read and change that twin’s world.

Your application never calls these. Only your agent, your setup, and your read-back do. Traffic here is recorded under tier=control and is kept separate from what your code sent.

Holding a control URL in your shell

The examples on this page, and everywhere else in these docs, write $CONTROL_URL for one twin’s control URL. veris sandbox services get <twin> prints it on the Control URL line, and --json puts the same value in control_url:

export CONTROL_URL=$(veris sandbox services get stripe --json | jq -r .control_url)

Each twin has its own, so set it again when you move to another twin.

Routes

RouteMethodWhat it does
/veris/healthGETIs it up, and what is it
/veris/manualGETShort operating notes for this twin: credentials, API versions, what faults it accepts
/veris/schemaGETEvery table and column, described in plain language
/veris/dataGETBare, returns row counts per table. With ?entity_type= returns rows
/veris/dataPOST / PATCH / DELETEAdd, edit, remove rows
/veris/filesPOSTUpload file bytes. See Files
/veris/requestsGETEvery request this twin served. See the trace
/veris/operationsGETEvery operation this twin serves. ?surface=rest, graphql or mcp narrows it
/veris/snapshotPOSTA full dump of this twin’s state, table by table, with its state_version
/veris/resetPOSTReset this twin only. Takes {"profile": "..."} or {"data": {...}}
/veris/reset-worldPOSTReturn the sandbox’s shared clock to live time
/veris/client/probePOSTRe-check that the registered callback destination is reachable

Reading a world

veris sandbox data get stripe veris sandbox data get stripe customers --limit 50 --offset 0
curl "$CONTROL_URL/veris/data" curl "$CONTROL_URL/veris/data?entity_type=customers&limit=50&offset=0"

Paged reads report a total. limit goes up to 1000.

Writing to a world

New rows come from a file keyed by twin name — here a customers.json holding {"stripe": {"customers": [{"id": "cus_1", "email": "a@example.test"}]}}:

veris sandbox data add customers.json
curl -X POST "$CONTROL_URL/veris/data" \ -H 'Content-Type: application/json' \ -d '{"data": {"customers": [{"id": "cus_1", "email": "a@example.test"}]}}'

veris sandbox data set stripe customers id=cus_1 email=b@example.test changes a row that already exists, and veris sandbox data delete stripe customers id=cus_1 removes one: the PATCH and DELETE of the same route.

Everything is validated before anything is written. A bad column, a bad type, or a broken relationship is refused with an explanation and the world is untouched.

The manual

GET /veris/manual returns the operating facts for one twin: which credentials it accepts, which API versions it serves, which error statuses you can arm, and anything specific about how it handles a repeated write. Read it before designing anything against that twin.

It does not list endpoints. GET /veris/operations does.

Reset

POST /veris/reset resets one twin. It does not touch the others and makes no promise that they still agree with each other afterwards.

It takes at most one replacement, data or profile. Any other key is refused with a 422 before anything changes, rather than being ignored.

For a coherent reset across every twin at once, use veris sandbox reset. See Reset, snapshot, baseline.

Routes that do not exist

/openapi.json, /docs and /redoc are not served on a twin. For the operations a twin serves use GET /veris/operations; for its tables and columns use GET /veris/schema.