POST to commit, GET to audit. Both
work in terms of intervals and integer GB; there are no individual blocks
or unit IDs.12345678910curl -X POST https://app.opencomputer.dev/api/capacity/reservations \ -H "X-API-Key: $OPENCOMPUTER_API_KEY" \ -H "Idempotency-Key: nightly-batch-2026-04-29" \ -H "Content-Type: application/json" \ -d '{ "intervals": [ { "startsAt": "2026-04-29T02:00:00Z", "endsAt": "2026-04-29T02:15:00Z", "capacityGb": 16 }, { "startsAt": "2026-04-29T02:15:00Z", "endsAt": "2026-04-29T02:30:00Z", "capacityGb": 16 } ] }'
12345678{ "reservationId": "9f67b8f7-7b91-4d2d-b1cb-19d0d0a14562", "createdAt": "2026-04-28T18:00:05Z", "intervals": [ { "startsAt": "2026-04-29T02:00:00Z", "endsAt": "2026-04-29T02:15:00Z", "capacityGb": 16 }, { "startsAt": "2026-04-29T02:15:00Z", "endsAt": "2026-04-29T02:30:00Z", "capacityGb": 16 } ] }
400 Bad Request and a
plain text error message:| Rule | Failure |
startsAt / endsAt UTC and 15-minute aligned | Misaligned values rejected. |
endsAt == startsAt + 15 minutes | Multi-interval spans rejected — enumerate intervals instead. |
capacityGb is a positive multiple of 4 | Other values rejected. The grain is 1 GB-hour (= 4 GB × 15 min). |
startsAt >= now + 30 minutes | Lead-time violation rejected. |
409 capacity_not_available with a list of every
problematic interval, so the client can retry with adjusted numbers in
a single round-trip:1234567891011{ "error": "capacity_not_available", "intervals": [ { "startsAt": "2026-04-29T02:00:00Z", "requestedGb": 80, "reservableGb": 28, "reason": "insufficient_capacity" } ] }
reason is one of:reason | Meaning |
insufficient_capacity | Request exceeds current reservableGb for the interval (either the platform-side limit or your org's max_memory_gb). |
concurrent_write | Another reservation for the same interval committed first; retry with the updated reservableGb. |
Idempotency-Key header. The server
stores the key with a hash of the request body and the response. Retries
return the cached response, even if the original write succeeded.| Behavior | Response |
| Same key, same body | Cached response from the first call. |
| Same key, different body | 409 idempotency_key_conflict. |
| No key | Request processed normally; retries are the client's problem. |
reserve-nightly-2026-04-29, so a client retry sends the same key.DELETE, no cancel endpoint, no transfer to a
different interval.12curl "https://app.opencomputer.dev/api/capacity/reservations?from=2026-04-01T00:00:00Z&to=2026-05-01T00:00:00Z" \ -H "X-API-Key: $OPENCOMPUTER_API_KEY"
123456789101112131415{ "from": "2026-04-01T00:00:00Z", "to": "2026-05-01T00:00:00Z", "reservations": [ { "reservationId": "9f67b8f7-7b91-4d2d-b1cb-19d0d0a14562", "createdAt": "2026-04-28T18:00:05Z", "intervals": [ { "startsAt": "2026-04-29T02:00:00Z", "endsAt": "2026-04-29T02:15:00Z", "capacityGb": 16 }, { "startsAt": "2026-04-29T02:15:00Z", "endsAt": "2026-04-29T02:30:00Z", "capacityGb": 16 } ] } ], "nextCursor": null }
| Query param | Required | Meaning |
from | yes | Return reservations whose createdAt >= from. |
to | yes | Return reservations whose createdAt < to. |
cursor | no | Pagination cursor from a previous response's nextCursor. |
limit | no | Max reservations per page. Server applies a ceiling. |
| Operation | Atomic across | On failure |
POST /reservations | All intervals in the request | Nothing reserved. |
reservableGb in their validation error.