The Engine Call Contract
Part of the MountDev Ops Workspace documentation. Updated November 5, 2026
MountDev Ops Workspace documentation | Updated November 5, 2026
Our Commitment
MountDev Ops is built security first. Your business data belongs to you, and you can export all of it at any time. We never use analytics or tracking of any kind inside MountDev Ops.
Every update passes all 2,733 automated checks before it ships, plus screen tests on 9 screen sizes for everything it changes.
What the Contract Is
Some work needs MountDev's shared engine, such as a check that needs a service MountDev runs for every account. The engine keeps nothing about any account. Your workspace calls it, hands over the facts and the keys that one call needs, and gets an answer back. When the call ends, the engine has stored nothing, and your workspace has kept your data and your keys.
This page is the one contract every such call follows. Every capability the engine offers uses the same envelope, the same errors, the same limits, and the same rules for what is never written down.
The Rules in Short
- Every call carries your account's own token. A token works for one account only.
- The keys a call needs travel in that call only. The engine never saves them and never logs them.
- The engine never writes to any account's tables. A capability is given only the facts and keys of the call, with no database and no storage, and returns a result. Your workspace decides what to keep.
- The engine records only ids and counts. It never records what was in a call.
- A call that is missing the keys its capability needs is refused before anything runs.
- Until account tokens are issued (plan item R1.2), every token is refused, so no call can run yet.
Making a Call
A call is one POST from your workspace to the engine over the service connection between them, at /internal/engine/call. It is not a public address. It has an Authorization: Bearer <token> header, a Content-Type: application/json header, and a JSON body, the request envelope.
| Field | Required | What it holds |
|---|---|---|
account | Yes | The account id the token belongs to, up to 64 letters, digits, _, and -. It must match the token. |
capability | Yes | The name of what to run, such as engine/ping: a group, a /, then a name, in lower case. |
idempotency_key | Yes | A key your workspace makes for this one attempt, 8 to 128 letters, digits, ., _, :, and -. See Repeating a Call. |
inputs | No | The facts the capability needs, as a JSON object. Empty when left out. |
credentials | Yes | The keys the capability needs, by name, as a JSON object with at most 32 entries. It is {} for a capability that needs no key, but it must always be sent. |
The engine checks the token first, before it reads the body, and then checks that account is the account the token belongs to. Token issuing is a separate step (plan item R1.2); this contract only says how a token is checked.
The Answer
A call that ran returns status 200 and the response envelope:
| Field | What it holds |
|---|---|
ok | true. |
result | What the capability returned. |
usage | Counts only, as whole numbers under short lower case names. calls is always there and is 1; a capability adds its own, such as messages. Your workspace turns these into the account's usage. |
retry | null when the call finished. |
idempotency_key | The key you sent, so you can match the answer to the attempt. |
A call that did not run, or failed, returns the error envelope:
{ "ok": false, "error": { "code": "credentials_missing", "message": "This call needs 2 keys that were not sent." }, "retry": null }message is one plain sentence. It never repeats a key or the token. retry is null, or { "after_seconds": 30 } (at most 3600) when trying the same call again later can work, and the same number is sent in a Retry-After header. Only a capability that fails because a service it called is busy or away can ask for a retry.
Error Codes
| Status | code | Meaning |
|---|---|---|
| 400 | bad_request | The body could not be read, is not valid JSON, or is not one JSON object. |
| 400 | credentials_missing | credentials was not sent as an object, has more than 32 entries, or lacks a key the capability needs. |
| 400 | bad_idempotency_key | The idempotency key is missing or the wrong shape. |
| 401 | unauthorized | The token is missing, wrong, or revoked. Nothing else about the call is read. |
| 403 | account_mismatch | The token is valid but belongs to a different account than account. |
| 404 | not_found | No such capability. |
| 405 | method_not_allowed | The call was not a POST. |
| 413 | too_large | The body is over the size limit. |
| 415 | unsupported_type | The call was not sent as JSON. |
| 422 | bad_inputs | The capability refused the facts. The message says what to fix in plain words. |
| 429 | rate_limited | Too many calls in a short time. A retry hint is sent. |
| 500 | handler_failed | The capability failed unexpectedly. The message is always "That did not work. Please try again." |
| 502 | upstream_unavailable | A service the capability called failed. A retry hint may be sent. |
| 503 | unavailable | The engine cannot take calls right now. |
Limits
| Limit | Value |
|---|---|
| Request body | 256 KB |
Keys in credentials | 32 |
| Idempotency key | 8 to 128 characters |
| Retry hint | Up to 3600 seconds |
Repeating a Call
The engine keeps nothing, so it cannot remember an earlier attempt, and it does not drop a repeated call by itself. It passes the idempotency_key to the capability, and a capability that does something outside the engine passes the same key to that service. Your workspace makes one key per attempt, reuses it only to repeat that same attempt after a retry hint, and drops a repeated answer itself. A capability that only reads can ignore the key.
What Is Never Recorded
- The engine writes one log line per call: the account id, the capability name, the status, the result code, the size of the call in bytes, and the time taken. Both ids are checked against their allowed shape first, so a bad value is logged as
-. The line never holdsinputs,credentials, the token, orresult. - A key from
credentialsnever appears in a log line, an error, or a response. Before any answer leaves the engine, every key value that was sent in the same call (3 characters or longer) is replaced with[removed], wherever it appears in the result, its names, and the error message. - The engine writes to no table of any account. A capability receives only the account, capability, inputs, credentials, and idempotency key, so it has nothing to write with, and the engine's tests fail if one tries.
- An account's token is never logged.
The First Capability
engine/ping exists so the contract can be tested end to end. It needs no key. Sent an optional message of text up to 200 characters, it returns { "pong": true, "account": "<the account>", "message": "<the message>" } and counts one message. It reads and writes nothing. Real capabilities are added one at a time, each with its own page, and each follows this contract without exception.
