How Cronevra works
Cronevra calls a URL you own, on a schedule you set, and records what happened. It does not run your code — every job is one outbound HTTP request and the response it gets back.
The request
A job is a method, a URL, and optionally headers, a bearer token and a JSON body. Methods: GET, POST, PUT, PATCH. A body is sent on POST, PUT and PATCH, and must be valid JSON.
DELETE is not offered. A scheduled DELETE against a mistyped URL runs unattended and cannot be undone, so it needs a confirmation step at save time that does not exist yet.
Bearer tokens and bodies are encrypted at rest and are never shown back to you after saving — if you lose one, replace it. Only https:// and http:// URLs on ordinary web ports are accepted, and credentials in the URL itself are refused.
Schedules
A schedule is a 5-field cron expression — minute, hour, day of month, month, day of week — evaluated in an IANA time zone you choose per job. The visual builder compiles down to the same expression, so there is one stored representation and daylight-saving is handled by the zone rather than by you.
How often a job may run depends on your plan; the fastest allowed interval is in the table below. A schedule quicker than your plan's floor is refused when you save it, not silently slowed down.
Retries
A failed attempt is retried up to your plan's limit, and immediately— there is no backoff between attempts. Every attempt is recorded as its own execution, including the ones that were retried, because “it succeeded on the third try” is exactly the diagnostic that gets hidden when only the final outcome is stored.
Not everything is retried. A refused destination or an oversized response will fail again identically, so retrying only spends your allowance — the table at the end says which codes are retried and which are not.
What your plan allows
| Free | Starter | Pro | Agency | |
|---|---|---|---|---|
| Active jobs | 1 | 25 | 75 | 300 |
| Executions per period | 1,000 | 100,000 | 500,000 | 2,000,000 |
| Fastest schedule | every 1 hour | every 5 minutes | every 1 minute | every 1 minute |
| Retries per run | 0 | 1 | 2 | 2 |
| Longest timeout | 10s | 30s | 30s | 30s |
| History kept | 3 days | 7 days | 30 days | 90 days |
| Response preview stored | 256 bytes | 1,024 bytes | 2,048 bytes | 4,096 bytes |
| Manual test runs per period | 250 | 2,000 | 10,000 | 50,000 |
One Evra subscription covers Cronevra at the matching level alongside every other product — see pricing.
Limits that no plan raises
These are safety limits rather than commercial ones. They bound what a single outbound request can cost in time, memory and bandwidth, so they apply on every plan including the top one.
- 30s absolute request timeout, and 2 retries, whatever a plan says.
- 1 MB of response downloaded before we stop — only a short preview is stored, so a larger body is never needed.
- 3 redirect hops followed, each one re-validated against the destination rules below.
- 64 KB request body, and 2,048 characters of URL.
Where requests can go
Cronevra's whole function is to fetch a URL a stranger typed in, from inside our infrastructure, so the destination check is deliberately paranoid and runs in two layers. The URL is checked when you save the job — scheme, port, credentials, hostname — and every address DNS returns is checked again at connect time, for the original request and for every redirect hop.
Private, loopback, link-local and cloud-metadata addresses are refused. We connect to the exact address that was approved rather than re-resolving the hostname, so DNS cannot change under us between the check and the connection. A URL that fails up front is blocked_ssrf; a redirect into private space is blocked_redirect.
Response previews
Only a short preview of each response is stored, sized by your plan, and it is redacted before it is written — not before it is displayed. Responses routinely echo the request: error pages print the Authorization header they received, OAuth endpoints hand back fresh tokens. Redacting at display time would leave the secret in the database for the next feature that reads the column.
When a run fails
Every failed execution carries one of these codes. Branch on the code, not the message.
| code | usually | retried? | meaning |
|---|---|---|---|
timeout | your endpoint | yes | The endpoint did not respond within the job's timeout. Raise the timeout, or make the endpoint answer faster and do its work in the background. |
dns_failure | the job's settings | yes | The hostname could not be resolved. Usually a typo or an expired domain. |
connection_refused | your endpoint | yes | Nothing was listening on that host and port. The service is down, or the port is wrong. |
tls_error | your endpoint | yes | The HTTPS certificate could not be verified — expired, self-signed, or for a different hostname. We do not skip verification. |
http_error | your endpoint | yes | The endpoint answered with a 4xx or 5xx status. The status and a redacted response preview are on the execution. |
too_many_redirects | your endpoint | no | The chain exceeded the redirect ceiling. Every hop is re-validated, so a loop stops here rather than running forever. |
response_too_large | your endpoint | no | The response passed the size ceiling and the download was stopped. We only ever store a short preview, so a large body is never needed. |
blocked_ssrf | the job's settings | no | The target resolved to a private, loopback, link-local or cloud-metadata address, or used a scheme or port we refuse. |
blocked_redirect | your endpoint | no | The request was fine but a redirect pointed somewhere private. The hop was refused rather than followed. |
secret_unavailable | us | no | The job's stored bearer token or body could not be decrypted, so the request was held back rather than sent without it. Re-save the secret on the job. |
usage_limit_reached | the job's settings | no | The organisation's executions for the period are spent. The job stays scheduled and resumes next period, or immediately on an upgrade. |
limits_unavailable | us | yes | We could not read the plan or the usage counter, so we could not tell whether this run was within your allowance and held it back. Distinct from usage_limit_reached on purpose: that one asserts the allowance is spent, which this is in no position to claim. |
unknown | us | yes | The request failed in a way that does not map to any of the above. If you see one, send us the execution id. |
Something here wrong or missing? contact@evra.pro — this page is generated from the same configuration the scheduler runs on, so if it disagrees with what you see, that is a bug worth hearing about.