Penv Cloud
Start free
Docs
Referencesince cloud@2026-09-17

Rate limits

The per-IP and per-identity request ceilings on the penv.cloud API, plan limits, the 429 response and back-off.

CeilingKeyed onLimitApplies to
IPFirst hop of x-forwarded-for1000 requests per minuteEvery call, before we read the credential
IdentityThe identity your credential namesPer your plan, belowEvery authenticated call
WorkspaceYour workspaceFree only, belowEvery authenticated call, on top of the identity ceiling

Every counter resets on a fixed one-minute window.

IP ceiling

We count it before authentication, so a flood of invalid tokens is turned away before any credential check.

It caps abuse, not your use, and sits well above one pipeline, a CI egress range or a NAT with many identities. The exchange routes under /api/v1/auth have no identity yet, so only this ceiling applies to them.

Identity ceiling

BucketOperations
readGET /api/v1/secrets, GET /api/v1/secrets/{address}, GET /api/v1/bulk-read-secrets, HEAD and GET /api/v1/envs/{org}/{project}/{environment} (penv run, penv pull), POST /api/v1/dynamic/{address}/lease
writePUT /api/v1/secrets/{address}, DELETE /api/v1/secrets/{address}, PUT /api/v1/envs/... (penv push), PATCH and DELETE /api/v1/envs/.../keys/... (penv set, penv unset)
PlanReads per minuteWrites per minute
Free24060
Pro2000300
EnterpriseCustomCustom

The pricing page shows the same numbers. Change your plan: billing and plans.

We key the counter on the identity, not the credential, so rotating your credential does not reset it. Two identities in one project count separately.

GET /api/v1/bulk-read-secrets and GET /api/v1/envs/... cost one read per value they open: an environment of 40 values spends 40 reads. We skip addresses that mint on demand, and they cost nothing. A HEAD, or a GET answered 304, costs one.

A bulk read that overshoots leaves the bucket over its ceiling until the minute ends; the next minute starts at zero.

Workspace ceiling

Free only. Every identity and every person's CLI in the workspace draws on it, at the same cost as the identity ceiling. We check your identity first, so a request the workspace ceiling refuses still counts against your identity's minute.

PlanReads per minuteWrites per minute
Free600150
Pro, EnterpriseNoneNone

Machine identities are free and unlimited (billing), so without this ceiling more identities would mean more Free throughput. The refusal is the same 429: retry-after gives the wait.

429 response

HTTP/1.1 429 Too Many Requests
retry-after: 17
{ "error": "rate_limited" }

retry-after is whole seconds until the window resets, never below 1. We return the same body for every ceiling, because naming the ceiling would reveal more about other tenants than about you.

POST /api/v1/dynamic/{address}/lease has a separate 429, ceiling_reached, when your environment trips our abuse ceiling on minting credentials. Codes: error codes.

Back-off

const res = await fetch(url, { headers: { authorization: `Bearer ${credential}` } });
if (res.status === 429) {
  const wait = Number(res.headers.get("retry-after") ?? 1) * 1000;
  await new Promise((done) => setTimeout(done, wait));
}

Sleep for retry-after seconds, then retry. Without the header, wait one second and double on each further 429, up to a minute.

PracticeEffect
Read once per job and pass values to one child processOne read per job; penv run works this way.
Use GET /api/v1/bulk-read-secrets instead of one request per keyFewer calls; still priced per value.
One machine identity per pipelineSeparate buckets; a shared identity shares one bucket.

Next: versioning.