Request limits
For api.nums.world · Verified . Other deployments may differ.
| Limit | Maximum | Applies to |
|---|---|---|
max_rows | 300,000 | Rows across context and query |
max_features | 4,095 | Feature columns, excluding the target |
max_cells | 60,000,000 | Cells in one request |
max_classes | 64 | Target classes for classification |
max_request_bytes | 1 GiB | Request size (1,073,741,824 bytes) |
max_response_bytes | 512 MiB | Response size (536,870,912 bytes) |
All limits apply together; the maximum row and feature counts cannot necessarily be used in the same request.
Check the latest values
Limits can change. Query GET /v1/limits to check the current values. No API key is required.
curl --fail --silent --show-error https://api.nums.world/v1/limits
Account allowance
Your account has a daily and a monthly allowance of cells and limits on
requests per minute and per hour. Use your API key with GET https://api.nums.world/v1/usage to check usage and allowances for that credential,
and every successful response carries them in metadata.quota.
When an allowance runs out the service answers 429 until it
resets. Nothing is invoiced and there is no overage.
Asking about your own table
GET https://api.nums.world/v1/estimate tells you whether a table of your shape
will be accepted. It needs no key, uploads nothing and runs the same checks as
admission control, so its verdict is the one a real request would get.
curl 'https://api.nums.world/v1/estimate?n_context=300000&n_query=1000&n_features=10'
{
"accepted": false,
"cells": 3010000,
"counts_against_allowance": 3010000,
"estimated_seconds": 99.1,
"model": "causilo-clf",
"deadline_s": 300.0,
"max_context_rows": 299000,
"code": "request_too_large",
"reason": "301,000 rows is over the 300,000 row limit."
}
Everything in the answer except the cell count, which is exact, is a
prediction from a fitted model. max_context_rows is the number of
context rows that fit at your column count, which is the figure a refusal
would have named. When a shape is refused, reason gives the same
explanation the refusal would give.
How requests are counted
A cell is one value in a table you send, counting the context and query rows together and excluding the target column. A request that names a stored context is counted for the context rows as well, because storing a context saves the upload and not the cells.
A request refused before it runs, whether by validation, a limit or a rate
limit, uses no cells, and neither does one whose response is too large to
return. It still counts towards the requests per minute and per hour, as every
request that reaches the service does. A request that ran and then failed uses
its cells; these are the
504 and the 502 described under
Errors.
A request you abandon is also counted in full. Disconnecting does not reach
the machine running the prediction, which finishes the work regardless, and a
call that has started cannot be cancelled, which is why
POST /v1/cancel answers 501. The Python client
reports this case as CausiloTimeout and does not retry, since a
retry would be counted again, so give it a timeout long enough to read the
answer the request has already used cells for.
Sending more than one call at a time
The rate limits are not a parallelism budget. Calls beyond what the service is running at the moment are queued and answered in turn, so none is refused for being concurrent, and the time spent waiting appears as latency.
Sending calls in parallel helps when tables are small and makes little difference when they are large, because large calls wait for the same GPU in turn. Many small queries against one table are faster as a single call with more query rows than as many calls.
A large table also delays the calls queued behind it, since it holds the queue for as long as it runs. Where latency matters, keep tables small and store the context instead of sending it again.
elapsed_s in the response measures the prediction alone and
excludes the time the call spent queued, so a client measuring wall-clock time
will see a larger number. The difference between the two is the time spent in
the queue.
Cell accounting and recovery
Cell cost: (n_context + n_query) * n_features. Feature columns exclude the target. Reusing a stored context still counts its rows; the saving is the upload.
| Condition | Status | Cells charged | Next action |
|---|---|---|---|
Refused before work startsvalidation_failed, request_too_large, rate_limited | 422, 413, 429 | 0 cells | Follow the error code and retryable flag |
Response cannot be returnedresponse_too_large | 413 | 0 cells | Do not retry the same request |
Work ran; answer timed out or could not be readupstream_unavailable, timeout | 502, 504 | Full request cells | Do not retry the same request |
Required store unavailable before workupstream_unavailable | 503 | 0 cells | Retry |
| You stop waiting for a started request Client exception: CausiloTimeout | Client timeout | Full request cells | Do not retry the same request |
POST /v1/cancel returns 501; a started request cannot be stopped. Requests refused before work still count towards request-rate limits.
| Measurement | Unit | Includes the queue |
|---|---|---|
metadata.elapsed_s | seconds | No |
| Client wall-clock time | seconds | Yes |
Client wall-clock time also includes the network round trip.