Control & Config
Every API request carries a script in q. It can carry more than that. These parameters decide how long the script may run, how far a loop may go, how patient a network call should be, and how much it is allowed to hold - sensible without them, and yours to change when the defaults do not suit the job.
How a limit is decided
You ask for a value; your tier decides the ceiling; the lower of the two applies. Asking for more than your tier allows is not an error - you get your tier’s ceiling and the response tells you what you actually got. A script written against a generous limit still runs on a small plan; it just runs within that plan.
curl -X POST https://ql.ocalt.com/api \
-d "identity=you@example.ocalt.com" \
-d "password=your_api_key" \
-d "execution_time=900" \
--data-urlencode 'q=SELECT ROWS FROM DB "warehouse" TABLE "movements" SET ?all
AFTER COUNT ?all SET ?n
AFTER EMIT ?n'
Time and Repetition
| Parameter | Default | What it governs |
|---|---|---|
execution_time | 300 | Seconds the whole script may run. Always seconds - never minutes, never a suffix |
loopmax | 1000000000 | Iterations any one WHILE or FOREACH may take before it is stopped |
depth_max | 64 | How deeply blocks and operations may nest inside each other |
on_timeout | error | error fails the request; partial returns whatever was emitted before the cut |
loopmax is not there to slow you down - a billion iterations is far more than any real job needs. It is there so that a loop whose exit condition is never met stops on its own instead of consuming your execution time and telling you nothing. When it trips, the error names the line, which is usually enough to see the mistake.Network
| Parameter | Default | What it governs |
|---|---|---|
fetch_timeout | 30 | Seconds any single FETCH or outbound request may wait |
fetch_max | 100 | Outbound requests one script may make in total |
fetch_redirects | 5 | Redirects followed before a fetch gives up |
A slow third party should not cost you your whole execution time. fetch_timeout is per request, so a script making twenty calls with a thirty-second timeout can still spend ten minutes waiting - which is why execution_time governs the total and always wins.
Memory and Size
Memory is what one script may hold at a single moment. It is not your storage, and deliberately so: storage is what you keep, memory is what a machine can hold in RAM while working, and there is far less of the second.
| Plan | memory_max | Storage, for comparison |
|---|---|---|
| Free | 128 MB | - |
| Starter | 1 GB | 8 GB |
| Pro | 4 GB | 64 GB |
| Enterprise | 8 GB | 256 GB |
| Syndicate Starter | 16 GB | 512 GB |
| Syndicate Pro | 32 GB | 1 TB |
| Syndicate Max | 48 GB | 8 TB |
| Syndicate Max B | 64 GB | 16 TB |
The two scales part company on purpose. A plan with sixteen terabytes of storage is not a plan that can hold sixteen terabytes in memory - no machine can. What the storage figure promises is that you can keep that much; what the memory figure promises is how much of it one script may have open at once.
That one number decides the rest:
| Limit | Equal to |
|---|---|
memory_max | Your plan’s figure above |
| Maximum POST size | The same figure - a request you cannot hold is a request you cannot process |
| Maximum file upload | The same figure, and it must also fit in your remaining storage |
output_max | The same figure. A response is built in memory before it is sent, so what you can emit is what you can hold |
Output is not separately capped. There is no fixed ceiling sitting under your plan waiting to truncate a large response - if you have four gigabytes of memory, you may emit four gigabytes. The only thing that stops a response is running out of the memory you were given, and that raises an error naming the figure rather than quietly cutting the output short.
An upload is checked twice: against your memory limit when it arrives, and against your remaining storage before it is written. A 4 GB upload on a plan with 4 GB of memory and 200 MB of space left is refused for the second reason, not the first.
Limits Persist
A limit you set is remembered. Send execution_time=900 once and
every later request in your namespace runs with it - including requests
you never make yourself.
That last part is the point. A visitor loading your Site Mode page cannot send parameters; their browser knows nothing about your plan. The limits your site runs under are the ones you set, whenever you last set them, from wherever you set them.
curl -X POST https://ql.ocalt.com/api \
-d "identity=you@example.ocalt.com" -d "password=your_api_key" \
-d "execution_time=900" -d "fetch_timeout=60" \
-d "q=EMIT 1"
(* From now on every script in this namespace gets 900 seconds and a
60-second fetch timeout — the API, the Console, a cron, and every
visitor hitting your Site Mode pages. *)
Sending a parameter on a later request changes the stored value again. Sending nothing leaves it as it was. To go back to the defaults, set them back explicitly - there is no reset, because a limit that silently returned to its default would be a limit you could not rely on.
memory_max is not one of these.
It is your plan’s ceiling rather than a preference, so it cannot be set,
raised, or persisted. Everything else in the table below can.Behaviour
| Parameter | Default | What it does |
|---|---|---|
dry_run | off | Parse and validate the script. Nothing executes, nothing is written, no quota is spent |
explain | off | Return how the script was understood - every verb, its arguments and how they chained |
trace | off | Return a line-by-line record of what ran and how long each statement took |
curl -X POST https://ql.ocalt.com/api \
-d "identity=you@example.ocalt.com" -d "password=your_api_key" \
-d "dry_run=1" \
--data-urlencode 'q=DELETE ROWS FROM DB "shopdb" TABLE "orders" WHERE "id" IS LESS THAN 100'
(* Returns whether it parses and what it would do. The rows are untouched. *)
dry_run is what an editor, a deployment check or a code review runs. It answers “is this valid, and what does it touch?” without the answer costing anything or changing anything.
Seeing What You Got
Ask for the limits in force and the response tells you, already clamped to your tier. Useful when a script behaves differently on two plans and you want to know why.
curl -X POST https://ql.ocalt.com/api \
-d "identity=you@example.ocalt.com" -d "password=your_api_key" \
-d "config=1" -d "q=EMIT 1"
(* {"execution_time":300,"loopmax":1000000000,"memory_max":"1GB",
"fetch_timeout":30,"fetch_max":100,"tier":"free"} *)
Full Parameter Reference
| Parameter | Default | Unit |
|---|---|---|
q | - | The script. Required |
identity | - | Your username or email. Required |
password | - | Your API key. Required |
execution_time | 300 | seconds |
loopmax | 1000000000 | iterations |
depth_max | 64 | levels |
fetch_timeout | 30 | seconds |
fetch_max | 100 | requests |
fetch_redirects | 5 | hops |
memory_max | your plan | bytes, or 1GB on Free |
output_max | your memory limit | bytes |
on_timeout | error | error or partial |
dry_run | 0 | 0 or 1 |
explain | 0 | 0 or 1 |
trace | 0 | 0 or 1 |
config | 0 | 0 or 1 - report the limits in force |
config_set | - | field:value - persist a limit for this namespace. A request parameter, never a script verb, so a script cannot raise its own ceiling. Every later request, Site Mode included, inherits it. |