The Claude API (/_claude/*)
An internal REST surface on the 4D side, meant for an automated agent: read and write blocks, run a host method, inspect Storage, reload the project. It is how a page is edited programmatically — never by hand-editing an export file.
Calling it
curl -sk -X POST "https://127.0.0.1:<port>/_claude/ping" \
-H "Host: <domain>" -H "Content-Type: application/json" -d '{}'
Four things that are not optional:
curl, not a tool that caches responses. A cached answer from a previous state is worse than no answer.- A body, even empty (
-d '{}'). Without it 4D answers 411 Length Required. - The
Hostheader whenever you target127.0.0.1, so the domain resolves. -kon the self-signed certificate. On Windows, PowerShell'sInvoke-WebRequestfails against it whatever you try; usecurl.exefromSystem32.
Answers are sometimes base64, occasionally nested twice:
… | sed 's/^base64://' | base64 -d | sed 's/^base64://' | base64 -d
Send accented values from a file, not inline. An accented vt_FieldLabel written straight into a -d '{…}' payload comes back corrupted. Use curl --data-binary @payload.json -H "Content-Type: application/json; charset=utf-8".
Authorisation
A remote call requires a token, generated with ClaudeAPI.generateToken($minutes). The token lives in Storage: there is only ever one, and a 4D restart loses it.
Warning: the token opens
execand the wholeStorage, so on a public site it is the keys to the house. Keep its lifetime short and revoke it. Do not expose/_claudeto the Internet.
Routes
| Route | What it does |
|---|---|
ping | Liveness, and tells you the build |
exec | Runs a host method through BSPH_EXECUTE_METHOD |
reload | RELOAD PROJECT — host code only |
storage | Reads Storage, or refreshes it |
data/<TABLE>/<action> | ORDA access, below |
admin/get|set | Reads or writes the encrypted admin templates by slug |
exec takes no parameters
It calls a host method by name and returns its Text result, if it has one. There is no way to pass arguments — a method that needs input has to read it from elsewhere. And never run a method that calls ALERT on a server: the dialog blocks the process with nobody to click it.
data actions
Read: query, get, all, first, validate, render-fields, render-style, page-tree, template-tree, export-template, files-integrity, migration-report.
Write: create, update, delete, set-property, place-template, import-template, capture-template, migration-apply, migration-files.
Writing is restricted by a whitelist, claude-api-write-tables.json, at the root of the host project. A table missing from it answers Write not allowed for table: … Check claude-api-write-tables.json — that is a configuration answer, not a bug.
There is no sort
Pagination is limit (default 20) and offset. There is no orderBy, and all returns records in storage order. Asking for "the most recent" with limit=1 therefore returns an arbitrary record — an easy way to draw conclusions from an old state. Page through and sort client-side.
Traps worth knowing before you write
admin/getreads memory, not disk. The template it returns comes fromStorage. If a dynamic function corrupted it in place, agetfollowed by asetwrites that corruption to disk permanently. Work on a.copy().- Never pre-generate uuids. Create the parent, read the
uuidKeythe API returns, then use it as the children'sparentUuid. AparentUuidof 32 spaces gives an empty page. - Object fields must be
{}, nevernull—properties,cssProperties,events. A null there has already crashed CSS generation at startup. - Creating blocks through the API does not extract Tailwind classes. The page renders unstyled until the class list is rebuilt. See Styling: the CSS cube and Tailwind.
- Long text values (
vt_Content) travel base64-encoded.
See also
- Reload or restart — what
reloaddoes and does not reload - The data model — the shape of what you are writing

