mirror of
https://github.com/runpod/runpod-plugins-official.git
synced 2026-09-14 18:44:38 +08:00
d0c4a7b2a1
* feat(runpod-migrate): add GraphQL / REST v1 -> REST v2 migration skill
Users migrating off REST v1 / GraphQL hand the job to a coding agent rather
than reading docs, so the skill is the surface that reaches them. It inventories
a codebase by API version, rewrites the call sites, and flags what breaks.
- SKILL.md: scope -> inventory -> brief breaking changes -> plan -> migrate ->
verify -> summarize. Summary separates "required" from "cleanup".
- scripts/rp_api_inventory.py: stdlib-only scanner. Buckets call sites by
generation (GraphQL / v1 / v1 field names / already-v2 / serverless job API /
SDK wrappers), suppresses hits that carry v2 context, and keeps prose and
rp-migrate:keep-v1 rollback paths out of the plan so --fail-on-legacy works
in CI.
- reference/: v1->v2 and GraphQL->v2 mapping tables, breaking changes split
into loud renames vs same-name-different-behavior vs removed capability,
v2 unlocks keyed to what the code already does, the RUNPOD_API_V1 rollback
flag, and a worked before/after migration.
- Catalog reads always request include=AVAILABILITY.
Mappings and error shapes were checked against the live v2 API; resources
created for verification were deleted. Two spec-vs-behavior gaps are documented
as observed: `timeout` comes back 0 rather than the documented 300000 default,
and a bad image is 500 {"error"} on v1 but 422 {title,status,detail} on v2.
* fix(runpod-migrate): unblock the inventory step and correct audit findings
Review pass over the skill: an independent accuracy audit against freshly
fetched specs plus read-only live calls, and execution of the commands the
docs tell users to run.
Blocking:
- The documented scanner invocation could not work. `python3
scripts/rp_api_inventory.py .` assumes the script is in the user's repo,
but it ships in the installed skill directory while the agent's working
directory is the customer's project. Step 1 failed with "No such file",
and every later step depends on it. Now resolved via CLAUDE_PLUGIN_ROOT,
the skill's own directory, or a search, with a self-check. Verified from a
simulated plugin install into a simulated customer repo, and asserted in
the inventory eval.
- The GPU pool lookup one-liner was a Python SyntaxError (escaped quotes in
an f-string expression), on the command that resolves a GPU type to its
serverless pool.
Corrections, each re-verified against the specs before applying:
- Template `category` was already an enum with the same values and default
in v1; it is not a v2 tightening.
- `minCudaVersion` and `volumeEncrypted` were listed as dropped from v1 pod
create; neither was ever in PodCreateInput.
- The 422 table omitted `gpu` from the endpoint-create required list — the
field most likely to be lost in a gpuTypeIds -> gpu.pools rewrite.
- globalNetworking was framed as a v2 unlock; the flag existed in v1, the
response object is what is new.
- Unknown-field rejection is `unevaluatedProperties: false` on the composed
Create/Update schemas, not `additionalProperties: false` everywhere.
- Rate-limit headers are omitted for rate-limit-exempt callers.
- The 400-vs-422 rule conflated schema and resource-level errors.
Added, both confirmed:
- Class 2: GraphQL `stockStatus` is High/Medium/Low/None but v2
`availability` is HIGH/MEDIUM/LOW/NONE. A rank table carried across stops
matching silently.
- Class 2: v2 `mounts` is far more restricted on PATCH than v1's
volumeInGb/volumeMountPath — kind fixed at create, volumeId immutable,
clearing rejected, partial entries rejected.
- `mounts.persistent` is deprecated and host-pinned, so a literal
volumeInGb translation inherits data-loss-on-host-failure.
Rejected one audit finding: the GraphQL network-volume mutations are real —
rphttp2, the v2 REST server, issues them — so the mapping row and scanner
signal stay. The public schema page simply omits them, as it omits
saveEndpoint and saveTemplate; graphql-to-v2.md now warns readers not to
treat that page as complete.
* fix(runpod-migrate): repair the verify gate and the gaps a cold run exposed
A fresh agent was given only the skill and the terse prompt "migrate my
codebase from runpod v1 to v2", ran the whole workflow on a fixture, and
reported back. Findings, verified and fixed.
--fail-on-legacy reported "4 files need migration" on a correctly migrated
tree. A gate that fails green builds gets deleted, and it teaches the agent
to stop trusting step 5. Two causes, both fixed:
- Comment detection only matched whole-line comments, so the skill's own
house style -- `"image": image, # was imageName` -- scored as a live v1
field. Comment detection is now quote-aware and handles trailing comments
(and does not mistake the `//` in `https://` for one).
- v2 context was matched per line, so `f"{BASE}/pods"` with `BASE` defined
eleven lines up read as a leftover v1 path. Base-URL constants are now
derived per file. The hardcoded name guesses (V2_BASE, v2_base, V2_URL)
are gone -- the migrated fixture had been passing only because it happened
to use one of them, which meant the corpus was written to match the
scanner rather than the other way round.
Shipped-code fixes:
- The GPU fallback snippet treated any non-201 as scarce capacity, so a 422
walked the entire preference list and raised "no GPU available" -- maximally
misleading during a migration, when 422 is the expected failure. Now fast-
fails on 422 and keeps the response body in the error.
Missing mappings, both silent failures:
- Billing `amount` -> `totalAmount`. The naive port is a KeyError, and it sits
one line from the far quieter /billing/endpoints trap.
- `dockerStartCmd` -> `args` joins an argv array into one string. Joining
["bash","-lc","python x.py"] naively runs python as the -lc script text.
No 422, no crash -- just the wrong command. Added as Class 2.
- `volumeInGb: 0` has no `mounts` translation; omit `mounts` entirely.
Workflow:
- Step 3 gains a third bucket, "decisions the user must make", so Class 3
capability loss has somewhere to land. Without it the cold run dropped
minRAMPerGPU and minVcpuCount with a code comment -- the exact silent drop
breaking-changes.md forbids.
- The scope instruction told the agent to ask when unclear, then supplied a
table resolving every phrasing, so it never fired. Now: infer, state, move
on; the real question is the step 3 fork.
- File order is dependency-blind (fewest call sites first), which put a
consumer ahead of the transport helper it imports. Shared helpers first.
- Commit hygiene forbade mixing behavior and version changes while the
opening pitch advertised one of those behavior changes as the payoff.
Reconciled: improvements land in the cleanup bucket.
- `rp-migrate: ignore` existed in the scanner but appeared nowhere in
SKILL.md, so the only documented escape hatch was `keep-v1` -- which
records a lie when used on a false positive. Both markers now documented
with the distinction, plus the residual cases the gate can still misread.
Placement: the 25-line benefits pitch opened the file but only pays off at
step 6; trimmed to four lines pointing at unlocks.md. The GPU fallback
rebuild -- the largest piece of new code a migration needs -- is now
signposted from step 4 where it is used, not only from step 2 where it lives.
* test(runpod-migrate): add scanner corpora and wire them into CI
The inventory scanner is the only executable in this repo, and its signal
table is 60+ interacting regexes with `unless` clauses — a one-line edit
breaks a distant case silently. Until now the only thing catching that was
me running fixtures by hand on one laptop, and those fixtures were not in
the repo.
Adds testdata/runpod-migrate/ (4 corpora, 68 KB) plus
hooks/check_migrate_scanner.py, run by CI alongside the other four hooks.
15 assertions, every one corresponding to a defect that actually shipped
during review:
- provision.js contains no "runpod" string, only GraphQL operation names.
A hand-written prefilter skipped it entirely.
- report.py has no URL, no import, no operation name — only a renamed
*response* field. Same prefilter bug, and the class of file a v2 rename
breaks silently in the callers of a wrapper.
- submit_job.py calls api.runpod.ai/v2 — the job API, one letter from the
control plane. Flagging it makes an agent rewrite working job submission.
- correct-v2/ is the load-bearing corpus: the scanner once reported "4 files
need migration" on a correctly migrated tree. A verify gate that fails on
correct code gets deleted, and teaches agents to distrust the verify step.
Deliberately at repo root, not under skills/runpod-migrate/: marketplace.json
installs that directory, so anything inside it ships to every user who
installs the plugin.
Mutation-tested rather than assumed — reverting the trailing-comment fix, the
per-file base-URL derivation, or the job-API bucket each turns the hook red.
live_verify.py stays out of the repo: it rents a real GPU and must never run
in CI.
* docs(runpod-migrate): teach the agent to check the spec itself
The skill handed the agent mapping tables and no way to question them. Both
OpenAPI documents are public and need no auth, but SKILL.md never said so —
the URLs appeared once, in a reference file, with no instruction to use them.
That matters more than a missing link. v2 is actively developed, so the
tables are a snapshot with a verification date; and the reference docs
already record two places where the running API contradicts its own spec.
An agent that hits a 422 naming a field it cannot place had no documented
recourse except guessing.
Adds a "Ground truth" section with commands verified by running them
verbatim:
- fetch either spec
- print a request body's fields with required ones starred, resolving allOf
composition (a naive read of the raw JSON misses it, which is how `gpu`
went missing from the documented endpoint-create required list)
- find which schemas mention a field name, for decoding a 422
And a precedence rule: observed live behavior > spec > these tables. Where
the API contradicts the spec, trust the API and say so in the summary, so
the user learns a documented default cannot be relied on. Drift in the
tables should be reported, not silently worked around.
Notes that GraphQL cannot be checked this way — introspection is disabled
and the public reference page is incomplete.
* docs(runpod-migrate): cover every resource with an inline before/after
Example coverage was uneven, and concentrated in the wrong file. The cold run
reported never opening worked-example.md at all -- "never opened unlocks.md or
worked-example.md and didn't miss them" -- so 12 of the skill's 30 code blocks
did no work in the one real trial. What did fire were examples sitting inline
in the mapping tables at the moment of need.
So these go where the agent already is: next to the table row they explain,
in rest-v1-to-v2.md and graphql-to-v2.md rather than in the narrative.
Newly covered, each a real gap:
- Network volumes had zero worked code despite being the flagship rename --
/networkvolumes -> /network-volumes is the example the ticket itself leads
with, and it carries three simultaneous changes (hyphenated path,
dataCenterId -> dataCenter, and the list envelope). Plus attaching one to a
pod, where `path` is now mandatory.
- CPU pods were one table mention. computeType + cpuFlavorIds + vcpuCount ->
a single `cpu` object, with the two CPU-only traps: mounts.persistent is
rejected outright, and vcpuCount must be a power of two inside the flavor's
advertised range.
- Pod lifecycle actions: four v1 paths collapsing into one body verb, with
reset having no equivalent and `actions` telling you what is legal now.
- Registries, standalone templates, and list-with-filters.
- A curl pair, so codebases that are not Python have an anchor. Examples were
13 Python to 1 JS.
- GraphQL: a full podFindAndDeployOnDemand conversion showing the four shape
changes a field-by-field rename misses -- comma-string ports to array, env
pair-list to map, dockerArgs to args, and string interpolation disappearing.
Every v2 body in the docs is now machine-checked against the live spec: 22
assertions covering required fields, unknown fields, the six enums, and the
nested config objects. All pass. The CPU example was checked against the live
catalog too -- cpu3c exists and vcpuCount 2 is inside its 2..32 range.
* docs(runpod-migrate): name the GraphQL volume mutations in the mapping table
A coverage audit over every v1 REST operation (37) and every customer-facing
GraphQL operation (23) found one real hole: createNetworkVolume,
updateNetworkVolume and deleteNetworkVolume existed only as a scanner signal
and as the prose "network volume mutations". An agent grepping the reference
for the operation name it found in the user's code got nothing back. Each is
now its own row with its v2 verb and path.
Also notes the /networkvolumes/{id}/update alias removal, which the pods,
endpoints and templates rows already called out.
The other 8 operations the audit flagged were a false alarm from the checker
normalizing {podId} while the docs use {id}; all are mapped.
* fix(runpod-migrate): report `ignore` and `keep-v1` as the distinct things they are
The scanner recorded only *whether* a line carried a suppression marker, not
which one, then rendered every marked hit as `keep-v1` / _(kept on purpose)_.
A repo whose remaining hits were all false positives was therefore described
as deliberately retaining v1 — the exact claim SKILL.md's marker table warns
against. Migrating a real codebase produced a report asserting "19 legacy call
sites kept on purpose" when it had none.
`ignore` was also documented as accepting `file` and `start`/`end` scope but
only ever matched at line scope: MARK_FILE/START/END were hardcoded to
`keep-v1`, and MARK_LINE's lookahead rejected `ignore file`, so it silently
did nothing.
- intentional_lines returns which marker applies, per line and per file.
- Hits carry `marker` instead of a boolean `intentional`.
- The verdict counts the two separately; rows label them differently.
- JSON `intentional_legacy` splits into `kept_on_purpose` and
`marked_false_positive`.
- keep-v1 wins a tie, since leaving a hit visible as legacy is the safer error.
Both still drop out of the plan and out of --fail-on-legacy, which was never
the broken part.
Adds a testdata/runpod-migrate/markers corpus covering both markers at line,
region and file scope, plus seven assertions including one that reads the
rendered report and fails if an ignore-marked row is labelled kept on purpose.
* docs: show how to point an agent at the worked examples
Plain-English prompts route fine, but golden paths carry no SKILL.md and are
never auto-loaded, and each skill's reference/*.md is progressive-disclosure —
so an agent planning a build has no reason to open either unless asked.
Adds an 'Ask for it by name' section to the repo README: six copyable prompts
covering planning a new service, migrating to REST v2, deploying existing code,
GPU choice, debugging, and cold starts, each paired with the specific paths and
reference docs it pulls in. Reduces the pattern to
[skill] + [read the examples first] + [task].
The plugin README's Usage list gains the same treatment, split into one-off
actions versus work you are designing.
* docs: simplify the example call-out to 'look at the examples'
The prompt table named a specific golden path per row, which made the reader
responsible for knowing which of 24 paths applied. Pointing at the examples in
general is enough — the agent picks. Keeps the one thing worth explaining: golden
paths have no SKILL.md and reference/*.md is progressive-disclosure, so neither
loads unless asked for.
* docs(runpod-migrate): correct what v2 /billing/endpoints actually returns
The reference said an unchanged /billing/endpoints call returns 'the wrong
numbers'. It does not — v2's /billing/endpoints is the Runpod public endpoints
billing route and reports that product's spend correctly.
The trap is narrower and worth stating precisely: the path survives the
migration but now answers a different question, so a caller that carries it
across gets an accurate total for a product it did not ask about — and 0 if it
runs no public endpoints, which reads as 'no serverless spend'.
Links the two reference tables to golden path 11 so the product is identifiable.
* feat: add /runpod:migrate slash command for the migration flow
* feat: bare /runpod:migrate defaults to full scope on current directory
* fix(runpod-migrate): correct four v2 claims the live spec contradicts
The reference tables were verified on 2026-08-10 and four claims no longer
hold. Three of them were Class-3 rows — the class SKILL.md tells the agent to
stop and ask the user about — so being wrong there does not surface as a 422.
It buys an interruption over a decision that does not exist, followed by a
deliberate workaround for a capability the user still has.
- `templateId` is accepted on pod and endpoint create *and* update. It is not a
422. What actually changed is the semantics: v2 resolves the template once at
request time and retains no link, so editing a template no longer rolls
changes out to existing resources. Moved to Class 2 as §13, since a quiet
behavior change is exactly that class.
- `allowedCudaVersions` / `minCudaVersion` moved under `gpu` rather than being
removed, nested there so they are unrepresentable on a CPU workload. Dropped
from Class 3, recorded as a rename in both mapping tables.
- CPU endpoints are writable via `cpu: [{id, vcpuCount}]`. Row removed.
- `/v2/billing/networkvolumes` is a 404; the path is `/v2/billing/network-volumes`.
The table warned about this exact hyphenation two rows earlier for the
resource path.
Two rows narrowed rather than removed, both of which overstated a removal:
- GPU fallback applies to pods only. An endpoint's `gpu.pools` is a list and v2
places workers on whichever listed pool has capacity, so the client-side loop
this skill teaches is rebuilding something v2 kept.
- `countryCodes` survives as a `/v2/catalog/gpus` read filter. It still cannot
constrain a create, so the row stands, but it can choose a target.
Also corrects the 422 table's required-field list: `image` is not
schema-required, because `templateId` can supply it.
The scanner's signal table carried the same three wrong claims as remediation
advice, so those rules move with the docs. All 22 scanner assertions still pass.
* ci: gate runpod-migrate's v2 claims against the spec
The four corrections in the previous commit were all found by diffing the docs
against the live spec, mechanically. Nothing in CI did that, which is why a
2026-08-10 verification pass could go stale unnoticed — catching it required
re-reading ~1,200 lines of tables by hand.
Two hooks, both stdlib-only:
- `check_migrate_tables.py` — every `METHOD /v2/...` claim in the skill's
markdown must exist in the spec with that method. Also checks method-less path
mentions, which the tables abbreviate as `…/v2/templates`. Paths the docs name
as counter-examples (`/v2/networkvolumes`, cited as the 404) need an entry in
EXPECTED_ABSENT with a reason, and the check fails if one of those starts
existing — an allowlist that silently rots is worse than no allowlist.
- `check_migrate_class3.py` — every identifier in the Class-3 "capability
removed" table is an assertion of absence, so existence alone falsifies the
row and no parsing of the prose column is needed. Request-body fields and
routes fail. Two softer outcomes are reported without failing: survives-as-a-
read-filter (the row is true, just incomplete) and GraphQL-only identifiers,
whose absence from a REST spec proves nothing and which are listed as
unchecked rather than counted as verified.
Both default to a vendored snapshot at `testdata/runpod-migrate/v2-openapi.json`
so the PR gate only fails on what a PR changed. `--live` runs the same checks
against api.runpod.io, wired to a weekly non-blocking `spec-drift` workflow:
upstream moving is real news, but not a reason to red-X an unrelated PR.
Current state: 45/49 path claims verified, 9/11 Class-3 rows verified absent,
1 read-filter note, 2 GraphQL-only rows left for a human.
* docs(runpod-migrate): give countryCodes a migration instead of a dead end
The Class-3 row and the scanner both stopped at "no v2 equivalent." That is
true about the *field* and misleading about the *task*: a country restriction
is rebuildable in v2, as a catalog lookup that resolves countries to data
centers, those IDs passed as `dataCenterIds` on create, and a check that the
resource landed where it was supposed to.
Presenting it as a removal is not a neutral omission. SKILL.md routes Class 3
to stop-and-ask, so a dead-end description hands the user a choice between
accepting a behavior change and keeping the call on v1 — when the actual answer
is a dozen lines of code. Keeping a v1 call they did not need to keep is a worse
outcome than the one the bucket exists to prevent.
- breaking-changes.md gains a worked recipe next to the GPU-fallback one.
- The recipe includes the post-create placement assert, because v2 documents
`dataCenterIds` as *preferred* and the spec does not say whether the scheduler
may override it. Unresolved, and called out as unresolved: if the requirement
is data residency, that distinction is the whole point, so the code verifies
`pod["dataCenterId"]` rather than trusting the request.
- SKILL.md reframes the stop-and-ask. The question is no longer "what should I
do here" but "was this a preference or a compliance requirement," which is the
part only the user can answer. Where a rebuild exists, show it while asking.
- The scanner message carries the recipe, not just the diagnosis, and
`countryCodes` moves out of the lumped "no equivalent" rule that hid it.
- Fixture and assertion added: the corpus never contained `countryCodes`, so
nothing would have caught this rule regressing to a dead end. Verified the
assertion fails when the advice is reverted.
* docs(runpod-migrate): dataCenterIds is enforced — verified against the live API
The previous commit hedged: v2 documents `dataCenterIds` as *preferred* data
centers, the spec does not say whether that is binding, and the recipe worked
around not knowing by asserting placement after create. Tested it instead.
Method: request an RTX 4090 — offered only in five EU data centers — while
naming `["US-KS-2","US-IL-1"]`, where it has no presence at all. That forces the
scheduler to choose between obeying the list and placing the pod, which a
happy-path test cannot do: a pod that lands where you asked proves nothing when
capacity was never scarce there.
Result: `400`, no pod. The control — the same body naming `EU-RO-1` — created
successfully and was terminated immediately. So the list is a hard restriction,
the scheduler will not place outside it to satisfy capacity, and it is a sound
basis for a data residency requirement. "Preferred" is misleading wording.
The post-create assert is dropped; it was insurance against an answer we now
have. Two things replace it:
- The 400 is documented, because the refusal presents as a capacity error and
never mentions data centers. Over-narrow the list and the message sends people
hunting for stock when the fix is widening the country list. That is the
second-likeliest failure in this migration after a malformed body.
- The stop-and-ask is sharpened. Since the restriction holds either way, the
preference-vs-compliance answer no longer changes the create — it changes the
*fallback*. A preference widens the list when capacity runs out; a compliance
requirement fails closed, which is the opposite of the GPU-fallback reflex the
same document teaches two sections earlier.
Also points compliance cases at `GET /v2/catalog/datacenters`, whose per-DC
`compliance` array (GDPR, ISO_IEC_27001, SOC_2_TYPE_2, HIPAA) is a sounder basis
for an allowed list than a country code. v1 gave users no way to say
"certified", so some of them said "in this country" and meant this.
* fix(runpod-migrate): address review findings at 089816f
Four of five findings from @runpod-Henrik's review, each reproduced before
fixing. The fifth is answered in the PR thread rather than changed.
1. `--fail-on-legacy` failed on correct v2 code. The `networkvolumes` and
`containerregistryauth` rules matched the bare token, unlike every other
path rule, so Go packages, Python modules and import paths all read as v1
call sites — 61 of 61 hits on one real repo. Both now require a leading `/`
and defer to V2_CONTEXT. Import and module-path lines are suppressed
separately, because `github.com/acme/internal/networkvolumes` carries the
slash that otherwise marks a real path.
2. We taught a call that 400s, in 17 places. `include=AVAILABILITY` requires
`product` and is invalid without it — 400 either way, no default, because
the same GPU can be scarce for POD and plentiful for SERVERLESS. Every call
site now names a product chosen for its context. This was the same failure
this PR set out to fix, one layer down: a claim the spec contradicts, in the
half of the URL nothing checked.
3. `.claude` was missing from SKIP_DIRS. Agent worktrees are full repo copies,
so findings were multiplied by however many exist — 10,763 reported against
1,821 real on runpod-flash. This ships as a Claude Code plugin, so its users
are exactly the people with that directory. Added, with `.worktrees`,
`.cache`, `.ruff_cache`, `.pnpm-store` and `bower_components`.
4. Nothing tested traversal, which is why 3 existed. Emptying SKIP_DIRS and
removing the filter outright both survived a mutation audit, because no
corpus contained a single skipped directory. New `skipped-dirs` corpus: one
real v2 file beside seven directories that each hold obvious v1 code,
asserting zero findings and a clean --fail-on-legacy. Both mutations now
die; the audit is 8/8.
5. The availability eval asserted the 400 form, so it would have re-certified
2 after the fix. Now asserts `product=` separately from the include.
Root cause of 2, fixed rather than papered over: check_migrate_tables.py only
verified paths. It now also verifies query parameters — that each one exists on
the path it is used with, and that required-together pairs appear together. The
pairs are derived from the spec's own prose ("Required with include=AVAILABILITY")
rather than hardcoded, so a new co-requirement is enforced as soon as v2
documents one. Verified by reverting a fixed line and watching the check fail.
2 lines
210 KiB
JSON
2 lines
210 KiB
JSON
{"openapi": "3.1.0", "info": {"title": "Runpod REST API", "version": "2.0.0", "description": "Runpod public REST API — v2"}, "servers": [{"url": "https://api.runpod.io", "description": "Runpod API v2 production server"}], "security": [{"bearerAuth": []}], "tags": [{"name": "Account", "description": "Account-scoped settings and primitives (SSH public keys)."}, {"name": "Pods", "description": "GPU and CPU pod lifecycle, configuration, actions, and log streaming."}, {"name": "Serverless", "description": "Serverless endpoint lifecycle, worker visibility, releases, and worker log streaming."}, {"name": "Templates", "description": "Reusable pod and endpoint configuration templates."}, {"name": "Network Volumes", "description": "Persistent network storage volumes for workloads."}, {"name": "Registries", "description": "Container registry credentials used to pull private images."}, {"name": "Catalog", "description": "Available GPU, CPU, data center, and public template catalog metadata."}, {"name": "Billing", "description": "Billing history and usage cost records across resource types."}], "components": {"securitySchemes": {"bearerAuth": {"type": "http", "scheme": "bearer", "bearerFormat": "Runpod API Key", "description": "Runpod API key authentication. Generate an API key in the Runpod console and send it in the `Authorization` header as `Bearer <api_key>`. Keys are scoped to the permissions granted when created; requests may return `403` when a valid key lacks access to the requested resource or action.\n"}}, "responses": {"UnauthorizedError": {"description": "Authentication failed because the bearer token is missing, malformed, expired, or invalid.", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "examples": {"missingBearerToken": {"summary": "Missing bearer token", "value": {"title": "Unauthorized", "status": 401, "detail": "missing bearer token"}}}}}}, "ForbiddenError": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "The bearer token is valid, but it does not grant access to the requested resource or action.", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "examples": {"insufficientAccess": {"summary": "Insufficient access", "value": {"title": "Forbidden", "status": 403, "detail": "access denied"}}}}}}, "BadRequestError": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "The request could not be processed because it is malformed or conflicts with request rules.", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "examples": {"badRequest": {"summary": "Bad request", "value": {"title": "Bad Request", "status": 400, "detail": "request could not be processed"}}}}}}, "NotFoundError": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "The requested resource was not found or is not accessible to the caller.", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "examples": {"notFound": {"summary": "Resource not found", "value": {"title": "Not Found", "status": 404, "detail": "resource not found"}}}}}}, "UnprocessableEntityError": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "The request body or parameters were syntactically valid but failed validation.", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "examples": {"validationFailed": {"summary": "Validation failed", "value": {"title": "Unprocessable Entity", "status": 422, "detail": "Request validation failed."}}}}}}, "MethodNotAllowedError": {"description": "The request method is not supported for the target path.", "headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}, "Allow": {"description": "Comma-separated methods supported by the target path.", "schema": {"type": "string"}, "example": "GET, POST"}}, "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "examples": {"methodNotAllowed": {"summary": "Method not allowed", "value": {"title": "Method Not Allowed", "status": 405, "detail": "The requested method is not allowed for this path."}}}}}}, "TooManyRequestsError": {"description": "The caller exceeded its per-user rate limit. The response identifies the window that was exceeded and how long to wait. The `RateLimit` and `RateLimit-Policy` headers (per the IETF ratelimit-headers draft) also accompany successful responses, so clients can track quota before a 429.\n", "headers": {"Retry-After": {"description": "Seconds to wait before retrying, per the exceeded window.", "schema": {"type": "integer"}, "example": 12}, "RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}, "examples": {"rateLimited": {"summary": "Rate limit exceeded", "value": {"title": "Too Many Requests", "status": 429, "detail": "rate limit exceeded for the minute window"}}}}}}}, "headers": {"RateLimit": {"schema": {"$ref": "#/components/schemas/RateLimitHeader"}}, "RateLimit-Policy": {"schema": {"$ref": "#/components/schemas/RateLimitPolicyHeader"}}}, "parameters": {"BillingStartTime": {"name": "startTime", "in": "query", "required": false, "description": "Start of the billing period (RFC 3339). Defaults to 30 days ago. Snapped down to the start of its bucketSize bucket so the window aligns with the returned records; provide a boundary-aligned value (e.g. midnight for bucketSize=day) to avoid widening.\n", "schema": {"type": "string", "format": "date-time"}, "example": "2026-05-01T00:00:00Z"}, "BillingEndTime": {"name": "endTime", "in": "query", "required": false, "description": "End of the billing period (RFC 3339), exclusive. Defaults to now. Snapped up to the end of the bucketSize bucket it lands in (unless already on a boundary) so the window aligns with the returned records.\n", "schema": {"type": "string", "format": "date-time"}, "example": "2026-06-01T00:00:00Z"}, "BillingBucketSize": {"name": "bucketSize", "in": "query", "required": false, "description": "Length of each billing time bucket. Defaults to day.", "schema": {"$ref": "#/components/schemas/BillingBucketSize"}}, "BillingLastN": {"name": "lastN", "in": "query", "required": false, "description": "Return the last N buckets of bucketSize, ending with the current (in-progress) bucket — e.g. lastN=100 with bucketSize=day is \"last 100 days\". The resolved window is aligned to bucket boundaries: startTime is the start of the earliest bucket (e.g. midnight of the earliest day) and endTime is the end of the current bucket. Mutually exclusive with startTime/endTime; provide one or the other, not both.\n", "schema": {"type": "integer", "minimum": 1}, "example": 30}, "CatalogIncludeParam": {"name": "include", "in": "query", "required": false, "description": "Comma-separated optional expansions. Supported value today: AVAILABILITY. This may expand with more include values in the future.", "style": "form", "explode": false, "schema": {"type": "array", "maxItems": 1, "items": {"$ref": "#/components/schemas/CatalogInclude"}}, "example": ["AVAILABILITY"]}, "GpuProductFilter": {"name": "product", "in": "query", "required": false, "description": "Comma-separated availability product contexts. Supported values: POD, CLUSTER, SERVERLESS. Required with include=AVAILABILITY, and valid only with it (400 either way). There is no default: the same GPU type can be scarce for pods and plentiful for serverless, so the context has to be stated rather than assumed.", "style": "form", "explode": false, "schema": {"type": "array", "items": {"$ref": "#/components/schemas/Product"}}, "example": ["POD", "SERVERLESS"]}, "GpuCountFilter": {"name": "count", "in": "query", "required": false, "description": "GPU count for availability and lowest-price calculations. Valid only with include=AVAILABILITY. Defaults to 1.", "schema": {"type": "integer", "minimum": 1, "default": 1}, "example": 2}, "GpuCloudFilter": {"name": "cloud", "in": "query", "required": false, "description": "Cloud type for availability and lowest-price calculations. Valid only with include=AVAILABILITY. Supported values: SECURE, COMMUNITY. Upstream default when omitted: SECURE.", "schema": {"$ref": "#/components/schemas/GpuCloudFilter"}}, "CountryCodesFilter": {"name": "countryCodes", "in": "query", "required": false, "description": "Comma-separated ISO 3166-1 alpha-2 country codes, uppercase, to constrain availability to — e.g. FR or FR,DE. Values within this filter use OR semantics. Valid only with include=AVAILABILITY (400 otherwise); a malformed entry is a 422. Scopes availability, lowest-price calculations and the dataCenters array to those countries, so a listed data center outside them is omitted rather than returned with availability NONE. On the list endpoint a GPU type with no data center in those countries drops out entirely; the single-GPU endpoint still returns the requested type, with availability NONE and dataCenters omitted, so a 404 keeps meaning the GPU type does not exist. Read the NONE on availability rather than the absence of dataCenters, which is also absent when availability was not requested.", "style": "form", "explode": false, "schema": {"type": "array", "items": {"type": "string", "pattern": "^[A-Z]{2}$"}}, "example": ["FR", "DE"]}, "CudaVersionsFilter": {"name": "cudaVersions", "in": "query", "required": false, "description": "Comma-separated CUDA versions to scope availability and lowest-price calculations to, matched exactly. Format: major.minor, e.g. 12.8 — a bare major is rejected here because it identifies no version. Valid only with include=AVAILABILITY (400 otherwise) and mutually exclusive with minCudaVersion (400 if both are sent); a malformed entry is a 422. Also narrows the returned cudaVersions array; omit it to enumerate every version offered.", "style": "form", "explode": false, "schema": {"type": "array", "items": {"type": "string", "pattern": "^\\d+\\.\\d+$"}}, "example": ["12.8", "12.6"]}, "MinCudaVersionFilter": {"name": "minCudaVersion", "in": "query", "required": false, "description": "Lowest acceptable CUDA version to scope availability and lowest-price calculations to, compared numerically. Format: integer major or major.minor, e.g. 12 or 12.1 — unlike the `gpu.minCudaVersion` body field on pod and endpoint create, a bare major is accepted here and means any release of that major, because this filter only widens a read. Valid only with include=AVAILABILITY (400 otherwise) and mutually exclusive with cudaVersions (400 if both are sent); a malformed value is a 422. Use this for an open-ended floor and cudaVersions for an exact set.", "schema": {"type": "string", "pattern": "^\\d+(\\.\\d+)?$"}, "example": "12.1"}, "CpuProductFilter": {"name": "product", "in": "query", "required": false, "description": "Comma-separated availability product contexts. Supported values for CPUs: POD, SERVERLESS. Required with include=AVAILABILITY, and valid only with it (400 either way). There is no default: availability differs by product.", "style": "form", "explode": false, "schema": {"type": "array", "items": {"$ref": "#/components/schemas/CpuProduct"}, "example": ["POD", "SERVERLESS"]}}, "CpuVCPUCountFilter": {"name": "vcpuCount", "in": "query", "required": false, "description": "Availability vCPU count. Valid only with include=AVAILABILITY. Must be a power of two.", "schema": {"type": "integer", "minimum": 2}, "example": 4}, "LogSourceParam": {"name": "source", "in": "query", "required": false, "description": "Log source to stream. Omit to include both container and system logs.", "schema": {"$ref": "#/components/schemas/LogSource"}}, "LogTail": {"name": "tail", "in": "query", "required": false, "description": "Number of historical lines to backfill before streaming. Defaults to\n100 when omitted; set `0` to stream live with no backfill. Maximum 5000.\nIgnored when `since` or `Last-Event-ID` is provided — the resume cursor\ndrives the backfill instead.\n", "schema": {"type": "integer", "minimum": 0, "maximum": 5000, "default": 100}}, "LogSince": {"name": "since", "in": "query", "required": false, "description": "RFC3339 timestamp to resume from. Ignored when `Last-Event-ID` is\nprovided. When set, the stream resumes from this point and `tail` is\nignored.\n", "schema": {"type": "string", "format": "date-time"}}, "LogLastEventID": {"name": "Last-Event-ID", "in": "header", "required": false, "description": "SSE reconnect cursor — a timestamp emitted by this endpoint. Takes\nprecedence over `since` and `tail`: when present, the stream resumes\nfrom this point. Sent automatically by EventSource on reconnect.\n", "schema": {"type": "string", "format": "date-time"}}}, "schemas": {"BaseContainerConfig": {"type": "object", "description": "Container configuration universal to every containerized resource. Compose ContainerConfig instead unless the resource cannot support private registries (clusters, until the upstream input accepts a registry credential).\n", "properties": {"args": {"type": "string", "description": "Arguments passed to the container entrypoint", "examples": [""]}, "disk": {"type": "integer", "minimum": 1, "description": "Container disk in GB (ephemeral, wiped on restart)", "examples": [50]}, "env": {"type": "object", "additionalProperties": {"type": "string"}, "description": "Environment variables as key-value pairs", "examples": [{"JUPYTER_PASSWORD": "hunter2"}]}, "image": {"type": "string", "description": "Docker image reference", "examples": ["runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404"]}, "ports": {"type": "array", "description": "Exposed ports, formatted as port/protocol", "items": {"type": "string"}, "examples": [["8888/http", "22/tcp"]]}}}, "ContainerConfig": {"description": "Reusable container configuration shared across templates, pods, and serverless endpoints. Adding a field here automatically propagates to all three resources.\n", "allOf": [{"$ref": "#/components/schemas/BaseContainerConfig"}, {"type": "object", "properties": {"registry": {"type": ["string", "null"], "description": "Container registry credential ID (for private images)", "examples": [null]}}}]}, "Mounts": {"type": "object", "additionalProperties": false, "description": "Storage mounts attached to a pod. At-most-one of `persistent` or\n`network` may be set today (mutually exclusive, enforced at the\nhandler with 400 if both are present). The `network` field is an\narray for forward compatibility with eventual multi-network-volume\nsupport, but `maxItems` is 1 today.\n\nPATCH semantics:\n- Omitting `mounts` or sending `{}` leaves the existing mount\n unchanged.\n- An explicit `network: []` is rejected with 400 (clearing mounts\n is not supported).\n- Mount kind is fixed at create — a PATCH that introduces a kind\n not present at create (persistent on a network pod, network on\n a persistent pod, or any mount on a previously-mountless pod)\n is rejected with 400.\n- The `volumeId` of a network mount is immutable; a PATCH that\n names a different `volumeId` is rejected with 400.\n- Partial mounts are not supported — every mount entry must\n include the full schema (`size` + `path` for persistent,\n `volumeId` + `path` for network). Missing required fields → 422.\n", "properties": {"persistent": {"$ref": "#/components/schemas/PersistentMount"}, "network": {"type": "array", "maxItems": 1, "items": {"$ref": "#/components/schemas/NetworkMount"}}}}, "TemplateMounts": {"type": "object", "additionalProperties": false, "description": "Storage mounts attached to a template. Templates support only a\nsingle persistent mount today; any `network` property is rejected\nwith 422 by the schema validator.\n\nPATCH semantics: omitting `mounts` or sending `{}` leaves the\nexisting mount unchanged.\n", "properties": {"persistent": {"$ref": "#/components/schemas/PersistentMount"}}}, "PersistentMount": {"type": "object", "required": ["size", "path"], "additionalProperties": false, "description": "Host-local persistent storage. Pinned to the pod's host machine — data\ndoes not survive a host failure. Disallowed on CPU pods. Mutually\nexclusive with NetworkMount. Deprecated: prefer NetworkMount for any\ndata you cannot recreate.\n", "properties": {"size": {"type": "integer", "minimum": 10, "description": "Host-local persistent storage in GB. Upstream enforces a 10 GB floor.", "examples": [20]}, "path": {"type": "string", "description": "Mount path inside the container. May be changed via PATCH.", "examples": ["/workspace"]}}}, "NetworkMount": {"type": "object", "required": ["volumeId", "path"], "additionalProperties": false, "description": "Reference to a NetworkVolume. Custom paths are honored at runtime on\nboth GPU and CPU pods. The underlying `volumeId` is immutable\npost-create; the mount `path` may be changed via PATCH.\n", "properties": {"volumeId": {"type": "string", "description": "ID of an existing NetworkVolume in the same data center as the pod.", "examples": ["vol_xyz"]}, "path": {"type": "string", "description": "Mount path inside the container. No default — must be specified explicitly.", "examples": ["/runpod-volume"]}}}, "GpuConfig": {"type": "object", "required": ["id"], "properties": {"id": {"type": "string", "description": "GPU type identifier", "examples": ["NVIDIA GeForce RTX 4090"]}, "count": {"type": "integer", "minimum": 1, "default": 1, "description": "Number of GPUs", "examples": [1]}}}, "CreateGpuConfig": {"description": "GPU request for a pod create. Carries the CUDA host constraints, which\nlive here rather than at the body's top level so they are\nunrepresentable on a CPU pod.\n", "allOf": [{"$ref": "#/components/schemas/GpuConfig"}, {"type": "object", "properties": {"allowedCudaVersions": {"type": "array", "items": {"type": "string", "pattern": "^\\d+\\.\\d+$"}, "description": "Acceptable CUDA versions for the host machine, as `major.minor`.\nOmit to accept any version. Matching is exact, so a version no\nmachine reports yields a capacity error rather than a fallback —\ndiscover valid values per GPU type via\n`GET /v2/catalog/gpus?include=AVAILABILITY&product=POD`\n(`cudaVersions`).\n\nA non-empty set is mutually exclusive with minCudaVersion (400\nif both are sent). An explicit `[]` states no constraint, so it\nmay accompany a floor.\n", "examples": [["12.8", "12.6"]]}, "minCudaVersion": {"type": "string", "pattern": "^\\d+\\.\\d+$", "description": "Lowest acceptable CUDA version for the host machine, as\n`major.minor`, compared numerically rather than as a decimal —\nso 12.11 is above 12.2. Use this for an open-ended floor and\nallowedCudaVersions for an exact set.\n\nMutually exclusive with a non-empty allowedCudaVersions (400 if\nboth are sent); an explicit `[]` there states no constraint and\nmay accompany this floor.\n", "examples": ["12.1"]}}}], "unevaluatedProperties": false}, "BaseCpuConfig": {"type": "object", "required": ["id", "vcpuCount"], "properties": {"id": {"type": "string", "description": "CPU flavor identifier, as returned by GET /v2/catalog/cpus.", "examples": ["cpu5c"], "minLength": 1}, "vcpuCount": {"type": "integer", "minimum": 2, "description": "Number of vCPUs. Must be valid for the selected CPU flavor and must be a power of two.", "examples": [4]}}}, "CreateCpuConfig": {"allOf": [{"$ref": "#/components/schemas/BaseCpuConfig"}], "unevaluatedProperties": false}, "CpuConfig": {"allOf": [{"$ref": "#/components/schemas/BaseCpuConfig"}, {"type": "object", "required": ["memory"], "properties": {"memory": {"type": "integer", "minimum": 1, "description": "Memory allocated to the pod in GB.", "examples": [16]}}}]}, "FlashBoot": {"type": "string", "description": "FlashBoot cold-start acceleration mode.\n- `OFF` — disabled\n- `FLASHBOOT` — enabled\n- `PRIORITY_FLASHBOOT` — enabled with priority capacity\n", "enum": ["OFF", "FLASHBOOT", "PRIORITY_FLASHBOOT"]}, "EndpointType": {"type": "string", "description": "Request-routing semantics for a modern serverless endpoint.\n- `QUEUE` — submit asynchronous or synchronous jobs through the managed queue.\n- `LOAD_BALANCER` — send requests directly to worker-defined HTTP paths.\n Configure via `env`: `PORT` (server port, default 80), `PORT_HEALTH`\n (health-check port, default 80), and `HEALTH_CHECK_PATH` (path the\n load balancer polls for worker health, default `/ping`).\n", "x-enum-varnames": ["EndpointTypeQueue", "EndpointTypeLoadBalancer"], "enum": ["QUEUE", "LOAD_BALANCER"]}, "QueueBasedRequestUrls": {"type": "object", "additionalProperties": false, "required": ["run", "runSync", "status", "stream", "cancel", "retry", "purgeQueue", "health"], "properties": {"run": {"type": "string", "format": "uri", "description": "URL for asynchronously submitting a queued job.", "examples": ["https://api.runpod.ai/v2/4m7x2k9q/run"]}, "runSync": {"type": "string", "format": "uri", "description": "URL for synchronously submitting a queued job. Accepts an optional `?wait=x` query parameter to control how long the request waits for job completion, defaulting to 90 seconds.", "examples": ["https://api.runpod.ai/v2/4m7x2k9q/runsync"]}, "status": {"type": "string", "format": "uri", "description": "Check the current state, execution statistics, and results of a previously submitted job.", "examples": ["https://api.runpod.ai/v2/4m7x2k9q/status/{job_id}"]}, "stream": {"type": "string", "format": "uri", "description": "Receive incremental results as they become available from a job that generates output progressively.", "examples": ["https://api.runpod.ai/v2/4m7x2k9q/stream/{job_id}"]}, "cancel": {"type": "string", "format": "uri", "description": "Stop an in-progress job or remove a queued job before it starts.", "examples": ["https://api.runpod.ai/v2/4m7x2k9q/cancel/{job_id}"]}, "retry": {"type": "string", "format": "uri", "description": "Requeue a failed or timed-out job without submitting a new request.", "examples": ["https://api.runpod.ai/v2/4m7x2k9q/retry/{job_id}"]}, "purgeQueue": {"type": "string", "format": "uri", "description": "Remove all pending jobs from the queue. Does not affect in-progress jobs.", "examples": ["https://api.runpod.ai/v2/4m7x2k9q/purge-queue"]}, "health": {"type": "string", "format": "uri", "description": "Overview of an endpoint's operational status.", "examples": ["https://api.runpod.ai/v2/4m7x2k9q/health"]}}}, "LoadBalancingRequestUrls": {"type": "object", "additionalProperties": false, "required": ["base", "health"], "properties": {"base": {"type": "string", "format": "uri", "description": "Base URL for worker-defined HTTP and WebSocket paths.", "examples": ["https://4m7x2k9q.api.runpod.ai"]}, "health": {"type": "string", "format": "uri", "description": "Health check endpoint the load balancer will periodically ping to decide if the worker is healthy enough to receive traffic. Configurable by setting the `HEALTH_CHECK_PATH` environment variable. Defaults to `/ping` if the variable is not set.", "examples": ["https://4m7x2k9q.api.runpod.ai/ping"]}}}, "EndpointRequestUrls": {"description": "Request URLs appropriate to the endpoint's top-level `type`.\nQueue-based endpoints provide job submission and management URLs;\nload-balancing endpoints provide `base` and `health` because their\nremaining paths are worker-defined.\n", "oneOf": [{"$ref": "#/components/schemas/QueueBasedRequestUrls"}, {"$ref": "#/components/schemas/LoadBalancingRequestUrls"}]}, "BaseEndpointGpuConfig": {"type": "object", "properties": {"pools": {"type": "array", "minItems": 1, "description": "Serverless GPU pool IDs (as returned by `GET /v2/catalog/gpus` in\n`pool`). Workers are placed on whichever listed pool has capacity.\nNarrow a pool down to specific cards with `excludedTypes`.\n", "items": {"type": "string"}, "examples": [["ADA_24"]]}, "excludedTypes": {"type": "array", "uniqueItems": true, "description": "GPU **type** IDs to subtract from the selected pools — the `id`\nfield of `GET /v2/catalog/gpus`, the same identifiers pods take in\n`gpu.id`. Workers run on every type in `pools` except these. Omit to\nuse the whole pool.\n\nPools stay the unit of selection; types are the unit of\nsubtraction. There is no inclusive allowlist: a card later added to\none of your pools becomes eligible, which is the honest reading of\n\"this pool, minus these\".\n\nTied to `pools`, because the two together are one selection:\nsupplying `pools` replaces that selection wholesale, so a `PATCH`\nsending `pools` **without `excludedTypes`** **clears** them —\nrestate them to keep them. A `PATCH` that omits `pools` leaves both\nthe pools and the exclusions untouched, so changing only a CUDA\nconstraint cannot widen a pinned endpoint.\n\nRejected with 400 if a value is not a GPU type in one of `pools`;\nupstream accepts unrecognized exclusions silently, so a typo would\notherwise produce a filter that does nothing. Surrounding whitespace\nis trimmed, so `\" NVIDIA L40\"` and `\"NVIDIA L40\"` mean the same card.\n", "items": {"type": "string", "pattern": "^\\s*[^-\\s]"}, "examples": [["NVIDIA L40"]]}, "count": {"type": "integer", "minimum": 1, "default": 1, "description": "GPUs per worker", "examples": [1]}}}, "EndpointGpuConfig": {"allOf": [{"$ref": "#/components/schemas/BaseEndpointGpuConfig"}, {"type": "object", "required": ["pools", "allowedCudaVersions", "minCudaVersion"], "properties": {"allowedCudaVersions": {"type": "array", "items": {"type": "string"}, "description": "Acceptable CUDA versions for worker placement, as `major.minor`. Empty means any version.", "examples": [[]]}, "minCudaVersion": {"type": ["string", "null"], "description": "Lowest acceptable CUDA version for worker placement, as `major.minor`. Null means no floor.", "examples": [null]}}}]}, "CreateEndpointGpuConfig": {"description": "GPU request for an endpoint create. Carries the CUDA constraints, which\nlive here rather than at the body's top level so they are\nunrepresentable on a CPU endpoint.\n", "allOf": [{"$ref": "#/components/schemas/BaseEndpointGpuConfig"}, {"type": "object", "required": ["pools"], "properties": {"allowedCudaVersions": {"type": "array", "items": {"type": "string", "pattern": "^\\d+\\.\\d+$"}, "description": "Acceptable CUDA versions for worker placement, as\n`major.minor`. Omit to accept any version (or inherit the\ntemplate's constraint when creating from `templateId`).\nMatching is exact — discover valid values per GPU type via\n`GET /v2/catalog/gpus?include=AVAILABILITY&product=SERVERLESS`\n(`cudaVersions`).\n\nA non-empty set is mutually exclusive with minCudaVersion (400\nif both are sent). An explicit `[]` states no constraint, so it\nmay accompany a floor.\n", "examples": [["12.8", "12.6"]]}, "minCudaVersion": {"type": "string", "pattern": "^\\d+\\.\\d+$", "description": "Lowest acceptable CUDA version for worker placement, as\n`major.minor`, compared numerically rather than as a decimal —\nso 12.11 is above 12.2. Use this for an open-ended floor and\nallowedCudaVersions for an exact set.\n\nMutually exclusive with a non-empty allowedCudaVersions (400 if\nboth are sent); an explicit `[]` there states no constraint and\nmay accompany this floor.\n", "examples": ["12.1"]}}}], "unevaluatedProperties": false}, "UpdateEndpointGpuConfig": {"description": "Partial GPU update — every field is optional and an omitted one is left\nunchanged. Unlike create, `pools` is optional, so changing only a CUDA\nconstraint does not require resending the pool list.\n\n`excludedTypes` requires `pools`, because the two are one selection and\nonly a supplied `pools` replaces it — an exclusion on its own would\notherwise be silently dropped.\n", "allOf": [{"$ref": "#/components/schemas/BaseEndpointGpuConfig"}, {"type": "object", "dependentRequired": {"excludedTypes": ["pools"]}, "properties": {"allowedCudaVersions": {"type": "array", "items": {"type": "string", "pattern": "^\\d+\\.\\d+$"}, "description": "Acceptable CUDA versions for worker placement, as\n`major.minor`. An explicit `[]` clears the constraint;\nomitting the field leaves it unchanged. Takes effect as\nworkers are replaced.\n\nA non-empty set is mutually exclusive with minCudaVersion (400\nif both are sent). An explicit `[]` states no constraint, so it\nmay accompany a floor.\nSetting one does not clear the other — clear it explicitly in\nthe same patch if the endpoint already carries it.\n"}, "minCudaVersion": {"type": "string", "pattern": "^$|^\\d+\\.\\d+$", "description": "Lowest acceptable CUDA version for worker placement, as\n`major.minor`. An explicit `\"\"` clears the floor; omitting the\nfield leaves it unchanged. Takes effect as workers are\nreplaced.\n\nMutually exclusive with a non-empty allowedCudaVersions (400 if\nboth are sent); an explicit `[]` there states no constraint and\nmay accompany this floor.\n", "examples": ["12.1"]}}}], "unevaluatedProperties": false}, "EndpointWorkers": {"type": "object", "additionalProperties": false, "properties": {"min": {"type": "integer", "minimum": 0, "description": "Minimum number of workers.", "examples": [0]}, "max": {"type": "integer", "minimum": 0, "description": "Maximum number of workers.", "examples": [5]}, "idleTimeout": {"type": "integer", "minimum": 1, "maximum": 3600, "description": "Seconds before idle workers scale down. Not applicable to queue-based\nendpoints scaling on `requestCount` — rejected on create/update and\nomitted from responses for that combination.\n", "examples": [5]}}}, "QueueDelayScaling": {"type": "object", "additionalProperties": false, "description": "Scale on queue wait time. Queue-based endpoints only.", "required": ["type", "queueDelay"], "properties": {"type": {"type": "string", "description": "Scaler discriminator. Always `QUEUE_DELAY` for this variant.", "enum": ["QUEUE_DELAY"]}, "queueDelay": {"type": "number", "format": "float", "minimum": 0.5, "description": "Adjusts the number of workers based on how long requests wait in the queue.", "examples": [4]}}}, "RequestCountScaling": {"type": "object", "additionalProperties": false, "description": "Scale on concurrent in-flight requests per worker. Required for\nload-balancing endpoints; also selectable for queue-based.\n", "required": ["type", "requestCount"], "properties": {"type": {"type": "string", "description": "Scaler discriminator. Always `REQUEST_COUNT` for this variant.", "enum": ["REQUEST_COUNT"]}, "requestCount": {"type": "integer", "minimum": 1, "description": "Adjusts the number of workers based on active in-flight requests.", "examples": [4]}}}, "EndpointScaling": {"description": "Autoscaling signal — a discriminated union on `type`: `QUEUE_DELAY`\n(queue-based endpoints only) or `REQUEST_COUNT`. The scaler is chosen\nindependently of the endpoint's routing `type` and can be switched on\nupdate.\n", "oneOf": [{"$ref": "#/components/schemas/QueueDelayScaling"}, {"$ref": "#/components/schemas/RequestCountScaling"}], "discriminator": {"propertyName": "type", "mapping": {"QUEUE_DELAY": "#/components/schemas/QueueDelayScaling", "REQUEST_COUNT": "#/components/schemas/RequestCountScaling"}}}, "Endpoint": {"allOf": [{"$ref": "#/components/schemas/ContainerConfig"}, {"type": "object", "required": ["id", "name", "workers", "scaling", "dataCenterIds", "networkVolumes", "timeout", "flashboot", "createdAt"], "properties": {"id": {"type": "string", "examples": ["ep_abc123"]}, "name": {"type": "string", "examples": ["my-inference"]}, "type": {"$ref": "#/components/schemas/EndpointType"}, "requestUrls": {"$ref": "#/components/schemas/EndpointRequestUrls"}, "gpu": {"anyOf": [{"$ref": "#/components/schemas/EndpointGpuConfig"}, {"type": "null"}]}, "cpu": {"type": "array", "minItems": 1, "description": "Eligible CPU configurations for each worker, in the order they\nwere submitted. Present for CPU endpoints and omitted for GPU\nendpoints. Memory is derived from the selected flavor's catalog\nRAM multiplier.\n", "items": {"$ref": "#/components/schemas/CpuConfig"}}, "workers": {"allOf": [{"$ref": "#/components/schemas/EndpointWorkers"}], "required": ["min", "max"]}, "scaling": {"$ref": "#/components/schemas/EndpointScaling"}, "dataCenterIds": {"type": "array", "items": {"type": "string"}, "examples": [["US-TX-3"]]}, "networkVolumes": {"type": "array", "items": {"type": "string"}, "examples": [["vol_abc"]]}, "timeout": {"type": "integer", "description": "Per-request execution timeout in milliseconds", "examples": [300000]}, "flashboot": {"$ref": "#/components/schemas/FlashBoot"}, "createdAt": {"type": "string", "format": "date-time", "examples": ["2026-03-13T20:00:00Z"]}}}]}, "ListEndpointsResponse": {"type": "object", "required": ["endpoints"], "properties": {"endpoints": {"type": "array", "items": {"$ref": "#/components/schemas/Endpoint"}}}}, "WorkerStatus": {"type": "string", "description": "Derived worker state, reconciled from the worker pod's lifecycle status\nand the live job-queue view.\n- `RUNNING` — actively processing a job\n- `IDLE` — ready and polling for jobs\n- `INITIALIZING` — starting up, not yet ready\n- `THROTTLED` — waiting on compute capacity\n- `UNHEALTHY` — failing health checks\n", "x-enum-varnames": ["WorkerStatusRunning", "WorkerStatusIdle", "WorkerStatusInitializing", "WorkerStatusThrottled", "WorkerStatusUnhealthy"], "enum": ["RUNNING", "IDLE", "INITIALIZING", "THROTTLED", "UNHEALTHY"]}, "Worker": {"type": "object", "required": ["id", "status", "gpuCount", "isStale"], "properties": {"id": {"type": "string", "examples": ["worker_abc"]}, "status": {"$ref": "#/components/schemas/WorkerStatus"}, "isStale": {"type": "boolean", "description": "True when the worker is running an older endpoint configuration than\nthe current one (e.g. mid rolling-update). This is the authoritative\nflag: it is derived from `version` vs the response's `endpointVersion`,\nexcept on legacy endpoints (`endpointVersion` 1) where it falls back\nto a container-image comparison.\n", "examples": [false]}, "version": {"type": ["integer", "null"], "description": "Endpoint configuration version this worker is running. Compare with\nthe response's `endpointVersion`. Null if unknown.\n", "examples": [4]}, "gpuCount": {"type": "integer", "minimum": 0, "description": "GPUs allocated to the worker.", "examples": [1]}, "image": {"type": ["string", "null"], "description": "Container image the worker is running.", "examples": ["my-org/sdxl-worker:latest"]}, "uptimeSeconds": {"type": ["integer", "null"], "minimum": 0, "description": "Seconds the worker has been running. Null until the worker is placed and running.", "examples": [3600]}, "gpuTypeId": {"type": ["string", "null"], "description": "GPU type the worker is placed on. Null until the worker is placed.", "examples": ["NVIDIA RTX 4090"]}, "dataCenterId": {"type": ["string", "null"], "description": "Data center the worker is placed in. Null until the worker is placed.", "examples": ["US-TX-3"]}, "startedAt": {"type": ["string", "null"], "format": "date-time", "description": "When the worker last started. Null if it has not started.", "examples": ["2026-03-26T00:00:00Z"]}}}, "WorkerSummary": {"type": "object", "description": "Histogram of the returned workers by status. The per-status counts are a\nroll-up of the `workers` array, so `running + idle + initializing +\nthrottled + unhealthy == total == len(workers)`.\n", "required": ["running", "idle", "initializing", "throttled", "unhealthy", "total"], "properties": {"running": {"type": "integer", "minimum": 0, "description": "Workers actively processing a job.", "examples": [2]}, "idle": {"type": "integer", "minimum": 0, "description": "Ready workers polling for jobs.", "examples": [1]}, "initializing": {"type": "integer", "minimum": 0, "description": "Workers starting up, not yet ready.", "examples": [0]}, "throttled": {"type": "integer", "minimum": 0, "description": "Workers waiting on compute capacity.", "examples": [0]}, "unhealthy": {"type": "integer", "minimum": 0, "description": "Workers failing health checks.", "examples": [0]}, "total": {"type": "integer", "minimum": 0, "description": "All workers currently allocated to the endpoint.", "examples": [3]}}}, "ListEndpointWorkersResponse": {"type": "object", "required": ["workers", "summary"], "properties": {"workers": {"type": "array", "items": {"$ref": "#/components/schemas/Worker"}}, "summary": {"$ref": "#/components/schemas/WorkerSummary"}, "endpointVersion": {"type": ["integer", "null"], "description": "The endpoint's current configuration version. A worker whose\n`version` differs is running stale config (see `worker.isStale`).\nNull if unknown.\n", "examples": [4]}}}, "ReleaseSource": {"type": "string", "description": "What produced the release.\n- `GIT_BUILD` — a completed GitHub build (see `buildId`)\n- `MANUAL` — a manual configuration change\n", "x-enum-varnames": ["ReleaseSourceGitBuild", "ReleaseSourceManual"], "enum": ["GIT_BUILD", "MANUAL"]}, "ReleaseDiffEntry": {"type": "object", "required": ["field", "old", "new"], "properties": {"field": {"type": "string", "description": "The changed configuration field. Top-level (e.g. `gpuCount`,\n`locations`) or template-scoped (e.g. `template.imageName`,\n`template.env`).\n", "examples": ["template.imageName"]}, "old": {"description": "Previous value, as raw JSON. Null when the field was added."}, "new": {"description": "New value, as raw JSON. Null when the field was removed."}}}, "Release": {"type": "object", "required": ["id", "source", "createdAt", "workerCount", "diff"], "properties": {"id": {"type": "string", "examples": ["rel_abc123"]}, "version": {"type": ["integer", "null"], "description": "The endpoint configuration version this release produced.", "examples": [4]}, "source": {"$ref": "#/components/schemas/ReleaseSource"}, "buildId": {"type": ["string", "null"], "description": "The GitHub build that produced this release. Set when `source` is\n`GIT_BUILD`; null for `MANUAL` releases. Fetch build detail/logs via\n`/v2/serverless/{id}/builds/{buildId}`.\n", "examples": ["build_abc123"]}, "createdByUserId": {"type": ["string", "null"], "description": "ID of the user who created the release."}, "workerCount": {"type": "integer", "minimum": 0, "description": "Workers currently running this release's version.", "examples": [2]}, "createdAt": {"type": "string", "format": "date-time", "examples": ["2026-03-13T20:00:00Z"]}, "diff": {"type": "array", "description": "Configuration fields that changed in this release.", "items": {"$ref": "#/components/schemas/ReleaseDiffEntry"}}}}, "RolloutSummary": {"type": "object", "required": ["inProgress", "workersOnLatest", "workersTotal", "percentOnLatest"], "properties": {"inProgress": {"type": "boolean", "description": "True while any worker is still running an older version.", "examples": [true]}, "workersOnLatest": {"type": "integer", "minimum": 0, "description": "Workers running the endpoint's current version.", "examples": [2]}, "workersTotal": {"type": "integer", "minimum": 0, "description": "All workers currently allocated to the endpoint.", "examples": [3]}, "percentOnLatest": {"type": "integer", "minimum": 0, "maximum": 100, "description": "Percentage of workers on the current version (0 when there are no workers).", "examples": [67]}}}, "ListEndpointReleasesResponse": {"type": "object", "required": ["rollout", "releases"], "properties": {"endpointVersion": {"type": ["integer", "null"], "description": "The endpoint's current configuration version. Null if unknown.", "examples": [4]}, "rollout": {"$ref": "#/components/schemas/RolloutSummary"}, "releases": {"type": "array", "description": "Release history, newest first.", "items": {"$ref": "#/components/schemas/Release"}}}}, "CreateEndpointRequest": {"allOf": [{"$ref": "#/components/schemas/ContainerConfig"}, {"if": {"not": {"required": ["templateId"]}}, "then": {"required": ["image"]}}, {"type": "object", "required": ["name", "type", "scaling"], "properties": {"gpu": {"$ref": "#/components/schemas/CreateEndpointGpuConfig"}, "name": {"type": "string", "minLength": 1, "examples": ["my-inference"]}, "scaling": {"$ref": "#/components/schemas/EndpointScaling"}, "type": {"allOf": [{"$ref": "#/components/schemas/EndpointType"}], "description": "Request-routing model. Required — it determines the valid scaler\nand request URLs, so it must be chosen explicitly on every create.\n"}, "cpu": {"type": "array", "minItems": 1, "uniqueItems": true, "description": "Eligible CPU configurations for each worker. Memory is derived from the\nselected flavor's catalog RAM multiplier. Exact duplicate configurations\nare rejected; the same flavor may be listed at different vCPU counts.\n", "items": {"$ref": "#/components/schemas/CreateCpuConfig"}}, "dataCenterIds": {"type": "array", "items": {"type": "string"}, "description": "Preferred data centers for placement. Omit or pass an empty array to let the scheduler choose."}, "flashboot": {"allOf": [{"$ref": "#/components/schemas/FlashBoot"}], "default": "OFF"}, "networkVolumes": {"type": "array", "items": {"type": "string"}}, "templateId": {"type": "string", "minLength": 1, "description": "ID of a serverless template to base this endpoint on. The\ntemplate is resolved at create time into the same container\nsettings you could otherwise spread into this body (image,\nargs, disk, ports, env, registry); explicit body fields\noverride the template's, except `env`, which is merged per\nkey with body values winning. The template's\nallowedCudaVersions seeds `gpu.allowedCudaVersions` when the\nbody omits it — but only for a GPU create, since a CPU endpoint\nhas no gpu block to seed into, and not when the body sets\n`gpu.minCudaVersion`, since seeding a set beside a floor would\nmanufacture the mutual-exclusion 400 from a valid request. Its\npod-specific startSsh/startJupyter flags are\nignored. Later template edits do not affect the endpoint.\nThe template may be one of your own or a public catalog\ntemplate — see `GET /v2/catalog/templates` (unknown or\ninaccessible ID → 404) — and must be a serverless template\n(→ 422).\n", "examples": ["30zmvf89kd"]}, "timeout": {"type": "integer", "default": 300000}, "workers": {"allOf": [{"$ref": "#/components/schemas/EndpointWorkers"}], "properties": {"min": {"type": "integer", "default": 0}, "max": {"type": "integer", "default": 3}, "idleTimeout": {"type": "integer", "default": 10}}}}}], "unevaluatedProperties": false, "if": {"required": ["type"], "properties": {"type": {"const": "LOAD_BALANCER"}}}, "then": {"properties": {"scaling": {"$ref": "#/components/schemas/RequestCountScaling"}}}}, "UpdateEndpointRequest": {"allOf": [{"$ref": "#/components/schemas/ContainerConfig"}, {"type": "object", "description": "Only provided fields are changed.", "properties": {"cpu": {"type": "array", "minItems": 1, "uniqueItems": true, "description": "Complete replacement CPU selection. Valid only for an existing CPU\nendpoint; endpoint compute family cannot be changed.\n", "items": {"$ref": "#/components/schemas/CreateCpuConfig"}}, "dataCenterIds": {"type": "array", "items": {"type": "string"}, "description": "Preferred data centers for placement. Omit or pass an empty array to let the scheduler choose."}, "flashboot": {"$ref": "#/components/schemas/FlashBoot"}, "gpu": {"$ref": "#/components/schemas/UpdateEndpointGpuConfig"}, "name": {"type": "string", "minLength": 1}, "networkVolumes": {"type": "array", "items": {"type": "string"}}, "scaling": {"$ref": "#/components/schemas/EndpointScaling"}, "templateId": {"type": "string", "description": "ID of a serverless template whose container settings are\napplied as if they were provided in this PATCH body (image,\nargs, disk, ports, env, registry). Explicit body fields\noverride the template's; `env` merges template and body per\nkey (body wins) and, per PATCH semantics, replaces the\nendpoint's env. One-time application — no link to the\ntemplate is retained. Must be one of your templates or a\npublic template (unknown or inaccessible ID → 404); must be\na serverless template (→ 422).\n", "examples": ["30zmvf89kd"]}, "timeout": {"type": "integer"}, "workers": {"$ref": "#/components/schemas/EndpointWorkers"}}}], "unevaluatedProperties": false}, "Utilization": {"type": "object", "description": "Single-value utilization percentage (0–100). Shared by `cpu` and `memory`.", "properties": {"util": {"type": "integer", "examples": [45]}}}, "PodGpuUtilization": {"type": "object", "description": "Per-GPU utilization metrics.", "properties": {"util": {"type": "integer", "examples": [94]}, "memoryUtil": {"type": "integer", "examples": [78]}}}, "PodRuntimePort": {"type": "object", "description": "Live port mapping for a running pod.", "properties": {"private": {"type": "integer", "examples": [8888]}, "public": {"type": ["integer", "null"], "examples": [43210]}, "type": {"type": "string", "examples": ["http"]}, "ip": {"type": ["string", "null"], "examples": ["45.23.12.1"]}}}, "PodRuntime": {"type": "object", "description": "Live utilization metrics for a running pod.", "properties": {"uptime": {"type": "integer", "description": "Seconds since the container started", "examples": [3600]}, "gpus": {"type": "array", "items": {"$ref": "#/components/schemas/PodGpuUtilization"}}, "cpu": {"$ref": "#/components/schemas/Utilization"}, "memory": {"$ref": "#/components/schemas/Utilization"}, "ports": {"type": "array", "items": {"$ref": "#/components/schemas/PodRuntimePort"}}}}, "PodStatus": {"type": "string", "description": "Lifecycle status of a pod.\n- `PROVISIONING` — pod is being allocated\n- `STARTING` — container is starting\n- `RUNNING` — container is healthy\n- `EXITED` — container exited (stopped)\n- `ERROR` — container is in an unrecoverable error state\n- `TERMINATED` — pod has been permanently deleted\n", "enum": ["PROVISIONING", "STARTING", "RUNNING", "EXITED", "ERROR", "TERMINATED"]}, "PodAction": {"type": "string", "description": "State transition to trigger on a pod.", "enum": ["start", "stop", "restart", "terminate"]}, "LogSource": {"type": "string", "description": "Log source to include in a log stream.\n- `container` — container stdout/stderr log stream\n- `system` — host lifecycle/userlogs stream\n", "x-enum-varnames": ["LogSourceContainer", "LogSourceSystem"], "enum": ["container", "system"]}, "Cloud": {"type": "string", "description": "Cloud tier.\n- `SECURE` — Runpod-owned datacenter hardware\n- `COMMUNITY` — community-hosted hardware\n", "enum": ["SECURE", "COMMUNITY"]}, "TemplateCategory": {"type": "string", "description": "Controls how the template is grouped and filtered in the Runpod console.\nIt does not affect hardware selection, scheduling, or billing.\n- `CPU` — CPU-only workloads\n- `NVIDIA` — NVIDIA GPU workloads\n- `AMD` — AMD GPU workloads\n", "enum": ["CPU", "NVIDIA", "AMD"]}, "PodGlobalNetworking": {"type": "object", "required": ["enabled"], "properties": {"enabled": {"type": "boolean", "description": "Whether global networking is enabled, giving the pod a private IP reachable across data centers. Derived from whether the pod has an assigned global-network address.", "examples": [true]}, "ip": {"type": "string", "description": "The pod's assigned global-networking IP. Present only when enabled.", "examples": ["10.65.1.42"]}, "internalDns": {"type": "string", "description": "Internal DNS name (`<podId>.runpod.internal`), reachable from other globally-networked pods in the same account. Present only when enabled.", "examples": ["gfj8b292vyg08g.runpod.internal"]}}}, "PodSshEndpoint": {"type": "object", "required": ["host", "port", "username", "command"], "description": "One way to reach the pod over SSH, as both its parts and a ready-to-run invocation.", "properties": {"host": {"type": "string", "description": "Hostname or IP to connect to.", "examples": ["ssh.runpod.io"]}, "port": {"type": "integer", "description": "TCP port to connect to.", "examples": [22]}, "username": {"type": "string", "description": "SSH username. For the proxy this is an opaque routing token, not a user account on the pod.", "examples": ["7h9k2m4n6p-64411eb2"]}, "command": {"type": "string", "description": "The equivalent `ssh` invocation, ready to run. Add `-i <path>` if the matching private key is not one of your default identities, and `-o StrictHostKeyChecking=no` to skip the host-key prompt on short-lived pods.", "examples": ["ssh 7h9k2m4n6p-64411eb2@ssh.runpod.io"]}}}, "PodSsh": {"type": "object", "required": ["proxy", "direct"], "description": "How to connect to this pod over SSH. Both variants authenticate with the account's registered SSH public keys (`PUT /v2/account/ssh-keys`), which reach the pod only if it was created with `startSsh` — a pod created without it has no SSH access regardless of what this block reports.", "properties": {"proxy": {"description": "Connection through Runpod's SSH proxy. Works without exposing a port and without a public IP, but carries an interactive shell only — SCP, SFTP, rsync, and port forwarding need `direct`. Null until the pod has a machine assignment.", "anyOf": [{"$ref": "#/components/schemas/PodSshEndpoint"}, {"type": "null"}]}, "direct": {"description": "Connection straight to the pod's sshd over its published `22/tcp` mapping. Supports the full SSH feature set. Null unless `22/tcp` is in `ports` and the running pod has been assigned a public port for it — so it is absent while the pod is provisioning or stopped.", "anyOf": [{"$ref": "#/components/schemas/PodSshEndpoint"}, {"type": "null"}]}}}, "SshKeys": {"type": "object", "required": ["keys"], "properties": {"keys": {"type": "array", "items": {"type": "string"}, "description": "The account's registered SSH public keys, one authorized_keys-style entry per element (`<type> <base64-key> [comment]`).", "examples": [["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILXGDN/SclOozk1xsDztpmhGiKkkrfQB9SKoO8dSIQQZ me@example.com"]]}}}, "UpdateSshKeysRequest": {"type": "object", "additionalProperties": false, "required": ["keys"], "properties": {"keys": {"type": "array", "items": {"type": "string", "pattern": "^(ssh|ecdsa|sk)-[^\\s]+ [^\\s]+([ \\t][^\\n\\r]*)?$"}, "description": "The full set of SSH public keys to register — this is a complete\nreplacement, not a merge. Each entry is an authorized_keys-style\nline: `<type> <base64-key> [comment]`, e.g. from\n`~/.ssh/id_ed25519.pub`. Send `[]` to remove all keys. These keys\nare provisioned into pods created with `startSsh` and\nauthenticate both SSH paths reported in the pod's `ssh` block.\n", "examples": [["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILXGDN/SclOozk1xsDztpmhGiKkkrfQB9SKoO8dSIQQZ me@example.com"]]}}}, "Pod": {"allOf": [{"$ref": "#/components/schemas/ContainerConfig"}, {"type": "object", "required": ["id", "name", "status", "actions", "image", "args", "disk", "mounts", "ports", "env", "registry", "cloud", "dataCenterId", "cudaVersion", "ssh", "template", "cost", "locked", "runtime", "createdAt", "startedAt", "globalNetworking"], "properties": {"id": {"type": "string", "examples": ["pod_abc123"]}, "name": {"type": "string", "examples": ["my-training-pod"]}, "status": {"$ref": "#/components/schemas/PodStatus"}, "actions": {"type": "array", "description": "Valid state transitions for the current status.", "items": {"$ref": "#/components/schemas/PodAction"}}, "mounts": {"$ref": "#/components/schemas/Mounts"}, "gpu": {"description": "Present for GPU pods; omitted from CPU pods.", "allOf": [{"$ref": "#/components/schemas/GpuConfig"}]}, "cpu": {"description": "Present for CPU pods; omitted from GPU pods.", "allOf": [{"$ref": "#/components/schemas/CpuConfig"}]}, "cloud": {"$ref": "#/components/schemas/Cloud"}, "dataCenterId": {"type": ["string", "null"], "description": "Data center where the pod is running (assigned by scheduler)", "examples": ["US-TX-3"]}, "cudaVersion": {"type": ["string", "null"], "description": "CUDA version reported by the host machine. Retained while the pod is stopped — a stopped pod keeps its machine assignment and resumes onto the same host. Null means unknown or not applicable (CPU pods, or a host that has not reported one), not that CUDA is absent.", "examples": ["12.8"]}, "ssh": {"allOf": [{"$ref": "#/components/schemas/PodSsh"}], "description": "SSH connection details, via the Runpod proxy or directly to the pod's published `22/tcp` port."}, "cluster": {"description": "Cluster membership; omitted from a standalone pod. Member pods are managed through `/v2/clusters/{id}` — they are excluded from `GET /v2/pods` by default (pass `includeClusterPods=true` to include them) and cannot be modified or deleted via the pod endpoints.", "allOf": [{"$ref": "#/components/schemas/PodCluster"}]}, "template": {"type": ["string", "null"], "description": "ID of the template this pod was created from", "examples": [null]}, "cost": {"type": "number", "format": "float", "description": "Current cost in USD per hour (0.0 when EXITED or TERMINATED)", "examples": [0.35]}, "locked": {"type": "boolean", "description": "Whether the pod is locked (prevents stopping or resetting)", "examples": [false]}, "globalNetworking": {"$ref": "#/components/schemas/PodGlobalNetworking"}, "runtime": {"description": "Live utilization metrics. Null when the pod is not RUNNING.", "anyOf": [{"$ref": "#/components/schemas/PodRuntime"}, {"type": "null"}]}, "createdAt": {"type": "string", "format": "date-time", "examples": ["2026-03-13T20:00:00Z"]}, "startedAt": {"type": ["string", "null"], "format": "date-time", "examples": ["2026-03-13T20:00:00Z"]}}}]}, "CreatePodRequest": {"allOf": [{"$ref": "#/components/schemas/ContainerConfig"}, {"type": "object", "required": ["name"], "description": "Request body for creating a pod. Exactly one of `gpu` or `cpu`\nmust be set — enforced at the handler layer. For CPU pods, memory\nis derived by the API from the selected flavor's RAM multiplier;\nclients provide only CPU flavor and vCPU count. CPU pods support\ncontainer disk and network volumes only; `mounts.persistent` is\ninvalid when `cpu` is set.\n\n`image` is required unless `templateId` is set.\n", "properties": {"name": {"type": "string", "minLength": 1, "examples": ["my-training-pod"]}, "cloud": {"allOf": [{"$ref": "#/components/schemas/Cloud"}], "default": "SECURE", "description": "Cloud tier. Defaults to `SECURE` when omitted."}, "cpu": {"$ref": "#/components/schemas/CreateCpuConfig"}, "dataCenterIds": {"type": "array", "items": {"type": "string"}, "description": "Preferred data centers for placement. Omit or pass an empty\narray to let the scheduler choose.\n", "examples": [["US-TX-3"]]}, "globalNetworking": {"type": "boolean", "default": false, "description": "Enable global networking, giving the pod a private IP reachable across data centers. Requires an NVIDIA GPU and a global-networking-enabled data center (both enforced upstream). See `GET /v2/catalog/datacenters` (`globalNetwork`) for eligible data centers.", "examples": [false]}, "gpu": {"$ref": "#/components/schemas/CreateGpuConfig"}, "mounts": {"$ref": "#/components/schemas/Mounts"}, "startJupyter": {"type": "boolean", "default": false, "description": "Create-time flag telling the provisioner to start JupyterLab:\ninjects a generated `JUPYTER_PASSWORD` environment variable,\nunless the request already sets one. Only images that honor\nthe convention start Jupyter from it (RunPod official images\ndo); expose `8888/http` in `ports` to reach it.\n\nNot part of the pod's readable config — never returned by\nGET and not changeable by PATCH.\n", "examples": [true]}, "startSsh": {"type": "boolean", "default": false, "description": "Create-time flag telling the provisioner to set up SSH\naccess: injects a `PUBLIC_KEY` environment variable carrying\nyour account's registered SSH public keys, unless the request\nalready sets one. **Requires registered keys** (`PUT\n/v2/account/ssh-keys`) — with none registered the flag does\nnothing and the pod has no SSH access. Only images that honor\nthe convention start sshd from it (all RunPod official images\ndo). Connect using the pod's `ssh` block; the `ssh.direct`\nvariant additionally needs a `22/tcp` entry in `ports`.\n\nNot part of the pod's readable config — never returned by\nGET and not changeable by PATCH.\n", "examples": [true]}, "templateId": {"type": "string", "minLength": 1, "description": "ID of a pod template to base this pod on. The template is\nresolved at create time into the same container settings you\ncould otherwise spread into this body (image, args, disk,\nports, env, registry, persistent mount, startSsh,\nstartJupyter, allowedCudaVersions); explicit body fields\noverride the template's, except `env`, which is merged per\nkey with body values winning. Sending either CUDA field\n(`gpu.allowedCudaVersions` or `gpu.minCudaVersion`) replaces\nthe template's CUDA constraint entirely, and CPU pods ignore\nit (like the persistent mount). The template is a one-time\nsource of settings: later template edits do not affect the\npod, and the created pod does not retain a link to the\ntemplate (`template` stays null). The template may be one\nof your own or a public catalog template — see\n`GET /v2/catalog/templates` (unknown or inaccessible ID →\n404) — and must not be a serverless template (→ 422). CPU\npods do not inherit a template's persistent mount.\n", "examples": ["30zmvf89kd"]}}}], "unevaluatedProperties": false, "if": {"not": {"required": ["templateId"]}}, "then": {"required": ["image"]}}, "UpdatePodRequest": {"allOf": [{"$ref": "#/components/schemas/ContainerConfig"}, {"type": "object", "properties": {"globalNetworking": {"type": "boolean", "description": "Enable (true) or disable (false) global networking. Takes effect on the next pod start/restart, not live. Requires an NVIDIA GPU and a global-networking-enabled data center (both enforced upstream). See `GET /v2/catalog/datacenters` (`globalNetwork`) for eligible data centers."}, "locked": {"type": "boolean", "description": "Lock the pod (true) or unlock it (false). Locked pods cannot be stopped or reset."}, "mounts": {"$ref": "#/components/schemas/Mounts"}, "name": {"type": "string", "minLength": 1}, "templateId": {"type": "string", "description": "ID of a pod template whose container settings are applied as\nif they were provided in this PATCH body (image, args, disk,\nports, env, registry — mounts are not applied on update).\nExplicit body fields override the template's; `env` merges\ntemplate and body per key (body wins) and, per PATCH\nsemantics, replaces the pod's env. One-time application —\nno link to the template is retained. Must be one of your\ntemplates or a public template (unknown or inaccessible ID\n→ 404); must not be a serverless template (→ 422).\n", "examples": ["30zmvf89kd"]}}}], "unevaluatedProperties": false}, "PodActionRequest": {"type": "object", "additionalProperties": false, "required": ["action"], "properties": {"action": {"$ref": "#/components/schemas/PodAction"}}}, "ListPodsResponse": {"type": "object", "required": ["pods"], "properties": {"pods": {"type": "array", "items": {"$ref": "#/components/schemas/Pod"}}}}, "ClusterType": {"type": "string", "description": "Cluster type. TRAINING is the generic distributed-training cluster; SLURM provisions a managed Slurm controller/compute topology; RAY provisions a managed Ray head/worker topology; APPLICATION is a general multi-node application cluster.", "enum": ["APPLICATION", "TRAINING", "SLURM", "RAY"], "examples": ["TRAINING"]}, "ClusterCompute": {"type": "object", "additionalProperties": false, "description": "The homogeneous compute shape of a cluster. Every pod in the cluster is identical: `podCount` pods, each with `gpuCountPerPod` GPUs of type `gpuTypeId`. Total GPUs = `podCount` * `gpuCountPerPod`.", "required": ["gpuTypeId", "gpuCountPerPod", "podCount"], "properties": {"gpuTypeId": {"type": "string", "minLength": 1, "description": "GPU type for every pod in the cluster, as returned by GET /v2/catalog/gpus.", "examples": ["NVIDIA H100 80GB HBM3"]}, "gpuCountPerPod": {"type": "integer", "minimum": 1, "description": "Number of GPUs on each pod. Bounded above by the GPU type's per-cloud maximum (GpuType.maxCount); the upstream rejects values beyond it.", "examples": [8]}, "podCount": {"type": "integer", "minimum": 2, "maximum": 250, "description": "Number of pods (nodes) in the cluster.", "examples": [4]}}}, "PodClusterRole": {"type": "string", "description": "A cluster member's role. Assigned for SLURM and RAY clusters; omitted for TRAINING/APPLICATION members.", "enum": ["SLURM_CONTROLLER", "SLURM_COMPUTE", "RAY_HEAD", "RAY_WORKER"]}, "PodCluster": {"type": "object", "additionalProperties": false, "description": "A pod's membership in a cluster.", "required": ["id", "rank"], "properties": {"id": {"type": "string", "description": "ID of the cluster this pod belongs to.", "examples": ["cluster_abc123"]}, "rank": {"type": ["integer", "null"], "description": "The pod's node rank within the cluster (NODE_RANK), or null until the index is assigned during provisioning. Rank 0 is the cluster's entry node (`Cluster.primary`); for SLURM it is the controller.", "examples": [0]}, "role": {"description": "SLURM or RAY role; omitted for TRAINING/APPLICATION clusters, which do not assign roles.", "allOf": [{"$ref": "#/components/schemas/PodClusterRole"}]}, "ip": {"type": "string", "description": "The pod's address on the cluster's private overlay network; omitted until the address is assigned.", "examples": ["10.65.0.2"]}}}, "ClusterNetwork": {"type": "object", "additionalProperties": false, "description": "The cluster's private VXLAN overlay network (shared by all member pods).", "required": ["cidr"], "properties": {"cidr": {"type": "string", "description": "The overlay network's CIDR block.", "examples": ["10.65.0.0/16"]}, "vxlanId": {"type": "integer", "description": "VXLAN network identifier; omitted until assigned.", "examples": [42]}, "vxlanPort": {"type": "integer", "description": "UDP port carrying the VXLAN traffic; omitted until assigned.", "examples": [4789]}}}, "ClusterPrimary": {"type": "object", "additionalProperties": false, "description": "The cluster's primary (master) node, through which the cluster is typically driven. Omitted until a primary pod has been placed.", "required": ["podId", "status"], "properties": {"podId": {"type": "string", "description": "ID of the primary member pod.", "examples": ["pod_node0"]}, "status": {"$ref": "#/components/schemas/PodStatus"}, "sshEndpoint": {"type": "string", "description": "Public SSH endpoint (`host:port`) for the primary node; omitted when the primary is not yet RUNNING or does not expose SSH (22/tcp).", "examples": ["1.2.3.4:22001"]}}}, "ClusterPodsSummary": {"type": "object", "additionalProperties": false, "description": "A lightweight summary of a cluster's member pods. Use `GET /v2/clusters/{id}/pods` to retrieve the full pod objects.", "required": ["total", "byStatus"], "properties": {"total": {"type": "integer", "description": "Number of member pods currently provisioned for the cluster.", "examples": [4]}, "byStatus": {"type": "object", "additionalProperties": {"type": "integer"}, "description": "Member pod counts keyed by pod status (the same values as `Pod.status`, e.g. RUNNING, PROVISIONING). Statuses with no pods are omitted.", "example": {"RUNNING": 3, "PROVISIONING": 1}}}}, "Cluster": {"type": "object", "description": "A cluster. Cluster-level fields describe the identity and homogeneous shape; `pods` is a lightweight summary of the members. Fetch the full member pods — with their container config, mounts, and runtime state — from `GET /v2/clusters/{id}/pods`.", "required": ["id", "name", "type", "compute", "pods", "createdAt"], "properties": {"id": {"type": "string", "examples": ["cluster_abc123"]}, "name": {"type": "string", "examples": ["my-training-cluster"]}, "type": {"$ref": "#/components/schemas/ClusterType"}, "compute": {"$ref": "#/components/schemas/ClusterCompute"}, "template": {"type": "string", "description": "ID of the template this cluster's pods were created from; omitted when they were not created from one.", "examples": ["tpl_abc"]}, "dataCenterId": {"type": "string", "description": "Data center the cluster is placed in (a cluster is always within a single data center). Derived from the member pods; omitted until at least one pod is placed.", "examples": ["US-TX-3"]}, "pods": {"$ref": "#/components/schemas/ClusterPodsSummary"}, "network": {"description": "The cluster's overlay network; omitted until the network is provisioned.", "allOf": [{"$ref": "#/components/schemas/ClusterNetwork"}]}, "primary": {"description": "The primary (master) node; omitted until a primary pod is placed. Its `sshEndpoint` is omitted until that pod is RUNNING with SSH exposed.", "allOf": [{"$ref": "#/components/schemas/ClusterPrimary"}]}, "createdAt": {"type": "string", "format": "date-time", "examples": ["2026-06-29T20:00:00Z"]}}}, "CreateClusterRequest": {"allOf": [{"$ref": "#/components/schemas/BaseContainerConfig"}, {"type": "object", "required": ["name", "type", "compute"], "description": "Request body for creating a cluster. `compute` defines the\nhomogeneous pod shape; the container configuration (image, env, ports,\n…) applies to every pod and can be spread from a template response.\nPrivate registries are not yet supported for clusters — there is no\n`registry` field here, unlike the other create requests.\n", "properties": {"compute": {"$ref": "#/components/schemas/ClusterCompute"}, "name": {"type": "string", "minLength": 1, "examples": ["my-training-cluster"]}, "type": {"$ref": "#/components/schemas/ClusterType"}, "dataCenterIds": {"type": "array", "items": {"type": "string"}, "description": "Preferred data centers for placement. Omit or pass an empty\narray to let the scheduler choose. A cluster is always placed\nwithin a single data center.\n", "example": ["US-TX-3"]}, "mounts": {"$ref": "#/components/schemas/Mounts"}, "startJupyter": {"type": "boolean", "default": false, "description": "Start Jupyter on every member pod, as on pod create."}, "startSsh": {"type": "boolean", "default": false, "description": "Provision SSH access on every member pod: injects a PUBLIC_KEY environment variable carrying your account's registered SSH public key. Same semantics as the pod create flag."}}}], "unevaluatedProperties": false}, "UpdateClusterRequest": {"type": "object", "additionalProperties": false, "minProperties": 1, "description": "Request body for updating a cluster. Only the cluster name can be\nchanged — this endpoint is a rename. Compute shape, type, and container\nconfiguration are fixed at creation.\n", "properties": {"name": {"type": "string", "minLength": 1, "examples": ["renamed-cluster"]}}}, "ListClustersResponse": {"type": "object", "required": ["clusters"], "properties": {"clusters": {"type": "array", "items": {"$ref": "#/components/schemas/Cluster"}}}}, "Template": {"allOf": [{"$ref": "#/components/schemas/ContainerConfig"}, {"type": "object", "required": ["id", "name", "image", "args", "disk", "mounts", "ports", "env", "registry", "serverless", "public", "category", "startSsh", "startJupyter", "allowedCudaVersions"], "properties": {"id": {"type": "string", "examples": ["tpl_abc"]}, "name": {"type": "string", "examples": ["My PyTorch Template"]}, "mounts": {"$ref": "#/components/schemas/TemplateMounts"}, "serverless": {"type": "boolean", "description": "Whether this template is for serverless workers (true) or pods (false)", "examples": [false]}, "public": {"type": "boolean", "description": "Whether this template is visible to other Runpod users", "examples": [false]}, "category": {"$ref": "#/components/schemas/TemplateCategory"}, "startSsh": {"type": "boolean", "description": "Whether containers created from this template get SSH access provisioned at startup (`PUBLIC_KEY` env injection).", "examples": [true]}, "startJupyter": {"type": "boolean", "description": "Whether containers created from this template start JupyterLab at startup (`JUPYTER_PASSWORD` env injection).", "examples": [false]}, "allowedCudaVersions": {"type": "array", "items": {"type": "string"}, "description": "Acceptable CUDA versions for containers created from this template, as `major.minor`. Empty means any version. Expanded into GPU pod and serverless endpoint creates; CPU pods ignore it.", "examples": [[]]}}}]}, "CreateTemplateRequest": {"allOf": [{"$ref": "#/components/schemas/ContainerConfig"}, {"type": "object", "required": ["name", "image"], "properties": {"name": {"type": "string", "minLength": 1, "examples": ["My PyTorch Template"]}, "allowedCudaVersions": {"type": "array", "items": {"type": "string", "pattern": "^\\d+\\.\\d+$"}, "description": "Acceptable CUDA versions for containers created from this\ntemplate, as `major.minor`. Omit to accept any version — see\nthe same field on `createPod` for matching semantics.\nExpanded into GPU pod and serverless endpoint creates; CPU\npods ignore it.\n", "examples": [["12.8", "12.6"]]}, "category": {"description": "Optional. Defaults to `NVIDIA` when omitted.", "allOf": [{"$ref": "#/components/schemas/TemplateCategory"}], "default": "NVIDIA"}, "mounts": {"$ref": "#/components/schemas/TemplateMounts"}, "public": {"type": "boolean", "default": false}, "serverless": {"type": "boolean", "default": false}, "startJupyter": {"type": "boolean", "default": true, "description": "Start JupyterLab in containers created from this template:\ninjects a generated `JUPYTER_PASSWORD` environment variable,\nunless `env` already sets one. Only images that honor the\nconvention start Jupyter from it (RunPod official images do);\nexpose `8888/http` in `ports` to reach it. Defaults to `true`\nwhen omitted, matching console-created templates.\n", "examples": [false]}, "startSsh": {"type": "boolean", "default": true, "description": "Provision SSH access in containers created from this template:\ninjects a `PUBLIC_KEY` environment variable carrying the\ndeployer's registered SSH public keys (`PUT\n/v2/account/ssh-keys` — with none registered the flag does\nnothing), unless `env` already sets one. Only images that\nhonor the convention start sshd from it (all RunPod official\nimages do); direct SSH also needs a `22/tcp` entry in\n`ports`. Defaults to `true` when omitted, matching\nconsole-created templates.\n", "examples": [true]}}}], "unevaluatedProperties": false}, "UpdateTemplateRequest": {"allOf": [{"$ref": "#/components/schemas/ContainerConfig"}, {"type": "object", "properties": {"allowedCudaVersions": {"type": "array", "items": {"type": "string", "pattern": "^\\d+\\.\\d+$"}, "description": "Acceptable CUDA versions for pods created from this template. An explicit `[]` clears the constraint; omitting the field leaves it unchanged."}, "category": {"$ref": "#/components/schemas/TemplateCategory"}, "mounts": {"$ref": "#/components/schemas/TemplateMounts"}, "name": {"type": "string", "minLength": 1}, "public": {"type": "boolean"}, "serverless": {"type": "boolean"}, "startJupyter": {"type": "boolean", "description": "Start JupyterLab at container startup (`JUPYTER_PASSWORD` env injection). See the create-time field for details."}, "startSsh": {"type": "boolean", "description": "Provision SSH access at container startup (`PUBLIC_KEY` env injection). See the create-time field for details."}}}], "unevaluatedProperties": false}, "ListTemplatesResponse": {"type": "object", "required": ["templates"], "properties": {"templates": {"type": "array", "items": {"$ref": "#/components/schemas/Template"}}}}, "NetworkVolume": {"type": "object", "required": ["id", "name", "size", "dataCenter", "type"], "properties": {"id": {"type": "string", "description": "Unique network volume identifier", "examples": ["agv6w2qcg7"]}, "name": {"type": "string", "description": "Human-readable name (not required to be unique)", "examples": ["my-dataset"]}, "size": {"type": "integer", "minimum": 10, "maximum": 4096, "description": "Allocated storage in GB", "examples": [50]}, "dataCenter": {"type": "string", "description": "Data center location; immutable after creation", "examples": ["EU-RO-1"]}, "type": {"allOf": [{"$ref": "#/components/schemas/VolumeType"}], "description": "Storage tier of this volume. Set at creation and immutable."}}}, "CreateNetworkVolumeRequest": {"type": "object", "additionalProperties": false, "required": ["name", "size", "dataCenter"], "properties": {"dataCenter": {"type": "string", "minLength": 1, "description": "Data center in which to create the volume", "examples": ["EU-RO-1"]}, "name": {"type": "string", "minLength": 1, "description": "Human-readable name", "examples": ["my-dataset"]}, "size": {"type": "integer", "minimum": 10, "maximum": 4096, "description": "Storage to allocate in GB", "examples": [50]}, "type": {"allOf": [{"$ref": "#/components/schemas/VolumeType"}], "description": "Storage tier for the volume. Optional. When omitted, the volume is\nprovisioned using the requested data center's default (primary)\nstorage tier. HIGH_PERFORMANCE provisions a high-performance (HPS)\nvolume; STANDARD provisions a standard volume. A volume's tier is\nimmutable after creation.\n"}}}, "UpdateNetworkVolumeRequest": {"type": "object", "additionalProperties": false, "minProperties": 1, "description": "Only the provided fields are updated. At least one field must be\npresent; an empty body is rejected.\n", "properties": {"name": {"type": "string", "minLength": 1, "description": "New human-readable name", "examples": ["renamed-volume"]}, "size": {"type": "integer", "minimum": 10, "maximum": 4096, "description": "New size in GB. Must be greater than or equal to the current size —\nnetwork volume storage cannot be reduced.\n", "examples": [100]}}}, "ListNetworkVolumesResponse": {"type": "object", "required": ["networkVolumes"], "properties": {"networkVolumes": {"type": "array", "items": {"$ref": "#/components/schemas/NetworkVolume"}}}}, "Registry": {"type": "object", "required": ["id", "name"], "properties": {"id": {"type": "string", "examples": ["reg_abc"]}, "name": {"type": "string", "examples": ["my-private-registry"]}}}, "CreateRegistryRequest": {"type": "object", "additionalProperties": false, "required": ["name", "username", "password"], "properties": {"name": {"type": "string", "minLength": 1, "examples": ["my-private-registry"]}, "password": {"type": "string", "minLength": 1, "description": "Registry password (write-only, not returned in responses)"}, "username": {"type": "string", "minLength": 1, "description": "Registry username (write-only, not returned in responses)"}}}, "ListRegistriesResponse": {"type": "object", "required": ["registries"], "properties": {"registries": {"type": "array", "items": {"$ref": "#/components/schemas/Registry"}}}}, "EcrDelegation": {"type": "object", "required": ["id", "delegatorUserId", "awsUser", "repository", "tag", "awsRegion", "createdAt"], "properties": {"id": {"type": "string", "description": "Delegation identifier", "examples": ["deleg_abc123"]}, "name": {"type": ["string", "null"], "description": "Optional name for the delegation", "examples": ["my-delegation"]}, "delegatorUserId": {"type": "string", "description": "User ID that created the delegation", "examples": ["user_xyz"]}, "awsUser": {"type": "string", "description": "AWS user/role being delegated", "examples": ["123456789"]}, "repository": {"type": "string", "description": "ECR repository name", "examples": ["runpod/deployment"]}, "tag": {"type": "string", "description": "ECR image tag", "examples": ["latest"]}, "awsRegion": {"type": "string", "description": "AWS region", "examples": ["us-east-2"]}, "dockerRegistryUri": {"type": "string", "description": "Formatted ECR registry URI for Docker login", "examples": ["123456789.dkr.ecr.us-east-2.amazonaws.com"]}, "createdAt": {"type": "string", "format": "date-time", "description": "When the delegation was created", "examples": ["2026-03-13T20:00:00Z"]}}}, "CreateDelegationRequest": {"type": "object", "additionalProperties": false, "required": ["resource"], "properties": {"resource": {"type": "string", "description": "ECR resource ARN", "examples": ["arn:aws:ecr:us-east-2:418399314813:repository/runpod/deployment"]}, "name": {"type": ["string", "null"], "description": "Optional name for the delegation", "examples": ["my-delegation"]}}}, "ListDelegationsResponse": {"type": "object", "required": ["delegations"], "properties": {"delegations": {"type": "array", "items": {"$ref": "#/components/schemas/EcrDelegation"}}}}, "GpuManufacturer": {"type": "string", "description": "Canonical GPU hardware manufacturer.", "x-enum-varnames": ["GpuManufacturerNVIDIA", "GpuManufacturerAMD", "GpuManufacturerUNKNOWN"], "enum": ["NVIDIA", "AMD", "UNKNOWN"]}, "GpuType": {"type": "object", "required": ["id", "name", "pool", "manufacturer", "memory", "secure", "community", "price", "maxCount"], "properties": {"id": {"type": "string", "description": "Individual GPU type identifier (use for pod creation)", "examples": ["NVIDIA GeForce RTX 4090"]}, "name": {"type": "string", "examples": ["RTX 4090"]}, "pool": {"type": ["string", "null"], "description": "Serverless GPU pool ID (use for serverless endpoint creation). Null if GPU is not in a serverless pool.", "examples": ["ADA_24"]}, "manufacturer": {"$ref": "#/components/schemas/GpuManufacturer"}, "memory": {"type": "integer", "description": "VRAM in GB", "examples": [24]}, "secure": {"type": "boolean", "description": "Available on secure cloud", "examples": [true]}, "community": {"type": "boolean", "description": "Available on community cloud", "examples": [true]}, "price": {"type": "object", "description": "List price in USD per hour for a **single** GPU of this type. Pod\nrates are quoted separately per cloud (`secure`, `community`);\n`serverless` is the rate for this GPU's pool. In every case the\nrate for a unit is the figure times `gpu.count`; the rate actually\nbilled for a pod is reported as `cost` on the pod itself.\n", "required": ["secure", "community"], "properties": {"secure": {"type": "number", "format": "float", "examples": [0.44]}, "community": {"type": "number", "format": "float", "examples": [0.31]}, "serverless": {"type": "number", "format": "float", "description": "Serverless list price per GPU per hour, from the `pool` this GPU\nbelongs to. Multiply by `gpu.count` for the per-worker rate.\nAbsent when the GPU is not in a serverless pool available to the\ncaller. Negotiated account discounts are not reflected.\n", "examples": [1.1]}}}, "maxCount": {"type": "object", "description": "The largest number of GPUs you can request on a single pod of this\ntype, quoted separately per cloud. A pod runs on one machine, so\nthis is the GPU count of the largest machine of this type Runpod\noperates in that cloud.\n\nThis is a ceiling, not a stock level — it does not mean that many\nGPUs are free right now. For current availability, request\n`include=AVAILABILITY&product=POD` and read `availability`\n(overall) or `dataCenters` (per data center).\n", "required": ["secure", "community"], "properties": {"secure": {"type": "integer", "examples": [8]}, "community": {"type": "integer", "examples": [4]}}}, "availability": {"description": "Overall GPU availability for the requested `product` contexts. Present only when requested with include=AVAILABILITY, which also requires `product`.", "$ref": "#/components/schemas/AvailabilityLevel"}, "dataCenters": {"type": "array", "description": "Per-datacenter GPU availability for the requested `product`\ncontexts, listing only the datacenters that offer this GPU in the\nrequested configuration. Present only when requested with\ninclude=AVAILABILITY, which also requires `product`, and omitted\nentirely when the configuration is unavailable everywhere.\n", "items": {"$ref": "#/components/schemas/DataCenterAvailability"}}, "cudaVersions": {"type": "array", "description": "CUDA versions offered by machines with this GPU type, each tagged\nwith current capacity. Present only when requested with\ninclude=AVAILABILITY, and scoped by the same filters as\n`availability` (`count`, `cloud`, `product`, and whichever of\n`cudaVersions` / `minCudaVersion` was supplied).\n\nMachines that report no CUDA version are skipped, so this property\nis absent entirely for a GPU type with none — AMD, for instance.\nTreat a missing `cudaVersions` the same as an empty one. A version\nabsent from a populated list is not offered for this GPU type.\n", "items": {"$ref": "#/components/schemas/CudaVersionAvailability"}}}}, "AvailabilityLevel": {"type": "string", "description": "Catalog stock availability level.", "enum": ["NONE", "LOW", "MEDIUM", "HIGH"]}, "Product": {"type": "string", "description": "Catalog product availability context. Availability is product-specific, so this is required whenever availability is requested.", "enum": ["POD", "CLUSTER", "SERVERLESS"]}, "CpuProduct": {"type": "string", "description": "CPU catalog product availability context. Availability is product-specific, so this is required whenever availability is requested.", "enum": ["POD", "SERVERLESS"]}, "CatalogInclude": {"type": "string", "description": "Catalog include expansion. Only AVAILABILITY is supported today; additional include values may be added in the future.", "enum": ["AVAILABILITY"]}, "DataCenterInclude": {"type": "string", "description": "Data center catalog availability expansion.", "enum": ["GPU_AVAILABILITY", "CPU_AVAILABILITY"]}, "GpuCloudFilter": {"type": "string", "description": "GPU availability cloud filter.", "enum": ["SECURE", "COMMUNITY"]}, "VolumeType": {"type": "string", "description": "Data center network volume storage type.", "enum": ["STANDARD", "HIGH_PERFORMANCE"]}, "CatalogResourceAvailability": {"type": "object", "required": ["id", "name", "availability"], "properties": {"id": {"type": "string", "description": "Catalog resource identifier.", "examples": ["NVIDIA GeForce RTX 4090"]}, "name": {"type": "string", "description": "Human-readable catalog resource name.", "examples": ["RTX 4090"]}, "availability": {"$ref": "#/components/schemas/AvailabilityLevel"}}}, "DataCenterAvailability": {"type": "object", "required": ["id", "name", "availability"], "properties": {"id": {"type": "string", "description": "Data center identifier.", "examples": ["US-CA-2"]}, "name": {"type": "string", "description": "Human-readable data center name.", "examples": ["US California 2"]}, "availability": {"$ref": "#/components/schemas/AvailabilityLevel"}}}, "CudaVersionAvailability": {"type": "object", "required": ["version", "available"], "properties": {"version": {"type": "string", "pattern": "^\\d+\\.\\d+$", "description": "CUDA version as `major.minor`, suitable for `gpu.allowedCudaVersions` on pod create.", "examples": ["12.8"]}, "available": {"type": "boolean", "description": "True when at least one machine on this CUDA version has free capacity now. False means the version is offered for this GPU type but is currently full, so a pod constrained to it will fail on capacity.", "examples": [true]}}}, "ListGpuTypesResponse": {"type": "object", "required": ["gpus"], "properties": {"gpus": {"type": "array", "items": {"$ref": "#/components/schemas/GpuType"}}}}, "CpuType": {"type": "object", "required": ["id", "name", "group", "vcpu", "ramGbPerVcpu", "price"], "properties": {"id": {"type": "string", "description": "CPU flavor identifier (use in cpu.id for pod creation)", "examples": ["cpu5c"]}, "name": {"type": "string", "description": "Human-readable flavor name", "examples": ["Compute-Optimized"]}, "group": {"type": "string", "description": "CPU generation group", "examples": ["Gen 5"]}, "vcpu": {"type": "object", "required": ["min", "max"], "properties": {"min": {"type": "integer", "examples": [2]}, "max": {"type": "integer", "examples": [32]}}}, "ramGbPerVcpu": {"type": "number", "format": "float", "description": "GB of RAM allocated per vCPU. Multiply by the chosen vCPU\ncount (within `vcpu.min`..`vcpu.max`) to get the total RAM\nfor an instance of this flavor. May be fractional.\n", "examples": [2.5]}, "price": {"type": "object", "required": ["securePerVcpu", "serverlessPerVcpu"], "properties": {"securePerVcpu": {"type": "number", "format": "float", "description": "Price for secure pods per vCPU. Multiply by the chosen vCPU\ncount (within `vcpu.min`..`vcpu.max`) to get the total price.\n", "examples": [0.04]}, "serverlessPerVcpu": {"type": "number", "format": "float", "description": "Price for serverless per vCPU. Multiply by the chosen vCPU\ncount (within `vcpu.min`..`vcpu.max`) to get the total price.\n", "examples": [0.03]}}}, "availability": {"description": "Overall CPU availability for the requested `product` contexts. Present only when requested with include=AVAILABILITY, which also requires `product`.", "$ref": "#/components/schemas/AvailabilityLevel"}, "dataCenters": {"type": "array", "description": "Per-datacenter CPU availability for the requested `product`\ncontexts, listing only the datacenters that offer this CPU flavor.\nPresent only when requested with include=AVAILABILITY, which also\nrequires `product`, and omitted entirely when the flavor is\nunavailable everywhere.\n", "items": {"$ref": "#/components/schemas/DataCenterAvailability"}}}}, "ListCpuTypesResponse": {"type": "object", "required": ["cpus"], "properties": {"cpus": {"type": "array", "items": {"$ref": "#/components/schemas/CpuType"}}}}, "DataCenter": {"type": "object", "required": ["id", "name", "region", "networkVolumeTypes", "compliance", "globalNetwork"], "properties": {"id": {"type": "string", "examples": ["US-TX-3"]}, "name": {"type": "string", "examples": ["US Texas 3"]}, "region": {"$ref": "#/components/schemas/DataCenterRegion"}, "globalNetwork": {"type": "boolean", "description": "Whether this data center supports global networking (private cross-datacenter pod-to-pod network).", "examples": [true]}, "networkVolumeTypes": {"type": "array", "items": {"$ref": "#/components/schemas/VolumeType"}, "description": "Network volume tiers this DC supports. Empty = none."}, "compliance": {"type": "array", "description": "Compliance certifications held by this data center", "items": {"$ref": "#/components/schemas/Compliance"}, "examples": [["GDPR", "ISO_IEC_27001", "SOC_2_TYPE_2"]]}, "gpuAvailability": {"type": "array", "description": "Availability of each GPU this data center offers. Present only when\nrequested with include=GPU_AVAILABILITY, and omitted entirely when\nthe data center offers no GPUs.\n", "items": {"$ref": "#/components/schemas/CatalogResourceAvailability"}}, "cpuAvailability": {"type": "array", "description": "Availability of each CPU flavor this data center offers. Present\nonly when requested with include=CPU_AVAILABILITY, and omitted\nentirely when the data center offers no CPU flavors.\n", "items": {"$ref": "#/components/schemas/CatalogResourceAvailability"}}}}, "DataCenterRegion": {"type": "string", "description": "Continental region containing the data center.", "examples": ["EUROPE"], "enum": ["NORTH_AMERICA", "SOUTH_AMERICA", "EUROPE", "ASIA", "MIDDLE_EAST", "AFRICA", "OCEANIA", "ANTARCTICA", "UNKNOWN"]}, "Compliance": {"type": "string", "description": "Compliance certifications.", "enum": ["GDPR", "ISO_IEC_27001", "ISO_14001", "PCI_DSS", "HITRUST", "SOC_1_TYPE_2", "SOC_2_TYPE_2", "SOC_3_TYPE_2", "ITAR", "FISMA_HIGH", "HIPAA", "RENEWABLE"]}, "ListDataCentersResponse": {"type": "object", "required": ["dataCenters"], "properties": {"dataCenters": {"type": "array", "items": {"$ref": "#/components/schemas/DataCenter"}}}}, "BillingTimeRange": {"type": "object", "description": "Half-open time range [startTime, endTime) in RFC 3339. On a record it is the time bucket; on a query echo it is the resolved window.\n", "required": ["startTime", "endTime"], "properties": {"startTime": {"type": "string", "format": "date-time", "description": "Start of the range, inclusive (RFC 3339).", "examples": ["2026-06-01T00:00:00Z"]}, "endTime": {"type": "string", "format": "date-time", "description": "End of the range, exclusive (RFC 3339).", "examples": ["2026-06-02T00:00:00Z"]}}}, "BillingBucketSize": {"type": "string", "enum": ["hour", "day", "week", "month", "year"], "x-enum-varnames": ["BillingBucketSizeHour", "BillingBucketSizeDay", "BillingBucketSizeWeek", "BillingBucketSizeMonth", "BillingBucketSizeYear"], "default": "day", "description": "Length of each billing time bucket.", "examples": ["day"]}, "BillingAmounts": {"type": "object", "description": "Total spend across all billable Runpod resources with each cost component broken out, fully prefixed by resource. Backs the aggregate record's amounts and the metadata totals.\n", "required": ["totalAmount", "podGpuAmount", "podCpuAmount", "podDiskAmount", "serverlessGpuAmount", "serverlessCpuAmount", "serverlessDiskAmount", "serverlessFeeAmount", "storageStandardAmount", "storageHighPerformanceAmount", "endpointAmount", "clusterGpuAmount", "clusterDiskAmount", "clusterNetworkingAmount"], "properties": {"totalAmount": {"type": "number", "format": "double", "description": "Total cost in USD for the bucket across all resources.", "examples": [42.34]}, "podGpuAmount": {"type": "number", "format": "double", "description": "GPU pod compute cost in USD for the bucket."}, "podCpuAmount": {"type": "number", "format": "double", "description": "CPU pod compute cost in USD for the bucket."}, "podDiskAmount": {"type": "number", "format": "double", "description": "Pod disk cost in USD for the bucket."}, "serverlessGpuAmount": {"type": "number", "format": "double", "description": "Serverless GPU compute cost in USD for the bucket."}, "serverlessCpuAmount": {"type": "number", "format": "double", "description": "Serverless CPU compute cost in USD for the bucket."}, "serverlessDiskAmount": {"type": "number", "format": "double", "description": "Serverless disk cost in USD for the bucket."}, "serverlessFeeAmount": {"type": "number", "format": "double", "description": "Serverless platform fee in USD for the bucket."}, "storageStandardAmount": {"type": "number", "format": "double", "description": "Standard network volume storage cost in USD for the bucket."}, "storageHighPerformanceAmount": {"type": "number", "format": "double", "description": "High-performance network volume storage cost in USD for the bucket."}, "endpointAmount": {"type": "number", "format": "double", "description": "Runpod public endpoint cost in USD for the bucket."}, "clusterGpuAmount": {"type": "number", "format": "double", "description": "Cluster GPU compute cost in USD for the bucket."}, "clusterDiskAmount": {"type": "number", "format": "double", "description": "Cluster disk cost in USD for the bucket."}, "clusterNetworkingAmount": {"type": "number", "format": "double", "description": "Cluster inter-node networking cost in USD for the bucket."}}}, "BillingRecord": {"description": "A single time-bucketed record of total spend across all billable Runpod resources, with each cost component broken out. Returned by GET /v2/billing.\n", "allOf": [{"$ref": "#/components/schemas/BillingTimeRange"}, {"$ref": "#/components/schemas/BillingAmounts"}]}, "PodBillingAmounts": {"type": "object", "description": "Pod cost components covering both GPU and CPU pods. Backs a record's amounts and the metadata totals.\n", "required": ["totalAmount", "gpuAmount", "cpuAmount", "diskAmount"], "properties": {"totalAmount": {"type": "number", "format": "double", "description": "Total pod cost in USD for the bucket.", "examples": [12.34]}, "gpuAmount": {"type": "number", "format": "double", "description": "GPU pod compute cost in USD for the bucket."}, "cpuAmount": {"type": "number", "format": "double", "description": "CPU pod compute cost in USD for the bucket."}, "diskAmount": {"type": "number", "format": "double", "description": "Pod disk cost in USD for the bucket."}}}, "PodBillingRecord": {"description": "A single time-bucketed pod billing record, covering both GPU and CPU pods. Returned by GET /v2/billing/pods.\n", "allOf": [{"$ref": "#/components/schemas/BillingTimeRange"}, {"$ref": "#/components/schemas/PodBillingAmounts"}, {"type": "object", "required": ["podId"], "properties": {"podId": {"type": "string", "description": "The pod this record bills. When the podId filter is set every record carries that id; otherwise one record is emitted per pod per bucket.\n", "examples": ["pod_abc123"]}}}]}, "ServerlessBillingAmounts": {"type": "object", "description": "Serverless cost components. Backs a record's amounts and the metadata totals.\n", "required": ["totalAmount", "gpuAmount", "cpuAmount", "diskAmount", "feeAmount"], "properties": {"totalAmount": {"type": "number", "format": "double", "description": "Total serverless cost in USD for the bucket.", "examples": [8.9]}, "gpuAmount": {"type": "number", "format": "double", "description": "Serverless GPU compute cost in USD for the bucket."}, "cpuAmount": {"type": "number", "format": "double", "description": "Serverless CPU compute cost in USD for the bucket."}, "diskAmount": {"type": "number", "format": "double", "description": "Serverless disk cost in USD for the bucket."}, "feeAmount": {"type": "number", "format": "double", "description": "Serverless platform fee in USD for the bucket."}}}, "ServerlessBillingRecord": {"description": "A single time-bucketed serverless billing record. Returned by GET /v2/billing/serverless.\n", "allOf": [{"$ref": "#/components/schemas/BillingTimeRange"}, {"$ref": "#/components/schemas/ServerlessBillingAmounts"}, {"type": "object", "required": ["serverlessId"], "properties": {"serverlessId": {"type": "string", "description": "The serverless endpoint this record bills. When the serverlessId filter is set every record carries that id; otherwise one record is emitted per serverless endpoint per bucket.\n", "examples": ["ep_abc123"]}}}]}, "EndpointBillingAmounts": {"type": "object", "description": "Runpod public endpoint cost. Backs a record's amounts and the metadata totals.\n", "required": ["totalAmount"], "properties": {"totalAmount": {"type": "number", "format": "double", "description": "Total public endpoint cost in USD for the bucket.", "examples": [3.21]}}}, "EndpointBillingRecord": {"description": "A single time-bucketed Runpod public endpoint billing record. Returned by GET /v2/billing/endpoints.\n", "allOf": [{"$ref": "#/components/schemas/BillingTimeRange"}, {"$ref": "#/components/schemas/EndpointBillingAmounts"}]}, "NetworkVolumeBillingAmounts": {"type": "object", "description": "Network volume storage cost, split into standard and high-performance. Backs a record's amounts and the metadata totals.\n", "required": ["totalAmount", "standardAmount", "highPerformanceAmount"], "properties": {"totalAmount": {"type": "number", "format": "double", "description": "Total network volume cost in USD for the bucket, across standard and high-performance storage.\n", "examples": [5.79]}, "standardAmount": {"type": "number", "format": "double", "description": "Standard storage cost in USD for the bucket."}, "highPerformanceAmount": {"type": "number", "format": "double", "description": "High-performance storage cost in USD for the bucket."}}}, "NetworkVolumeBillingRecord": {"description": "A single time-bucketed network volume billing record, split into standard and high-performance storage. Returned by GET /v2/billing/network-volumes.\n", "allOf": [{"$ref": "#/components/schemas/BillingTimeRange"}, {"$ref": "#/components/schemas/NetworkVolumeBillingAmounts"}, {"type": "object", "required": ["networkVolumeId"], "properties": {"networkVolumeId": {"type": "string", "description": "The network volume this record bills. When the networkVolumeId filter is set every record carries that id; otherwise one record is emitted per network volume per bucket.\n", "examples": ["vol_abc123"]}}}]}, "ClusterBillingAmounts": {"type": "object", "description": "Cluster cost components (GPU-only, no CPU). Backs a record's amounts and the metadata totals.\n", "required": ["totalAmount", "gpuAmount", "diskAmount", "networkingAmount"], "properties": {"totalAmount": {"type": "number", "format": "double", "description": "Total Instant Cluster cost in USD for the bucket.", "examples": [99.0]}, "gpuAmount": {"type": "number", "format": "double", "description": "Cluster GPU compute cost in USD for the bucket."}, "diskAmount": {"type": "number", "format": "double", "description": "Cluster disk cost in USD for the bucket."}, "networkingAmount": {"type": "number", "format": "double", "description": "Cluster inter-node networking cost in USD for the bucket."}}}, "ClusterBillingRecord": {"description": "A single time-bucketed cluster billing record; clusters are GPU-only (no CPU component). Returned by GET /v2/billing/clusters.\n", "allOf": [{"$ref": "#/components/schemas/BillingTimeRange"}, {"$ref": "#/components/schemas/ClusterBillingAmounts"}, {"type": "object", "required": ["clusterId"], "properties": {"clusterId": {"type": "string", "description": "The cluster this record bills. When the clusterId filter is set every record carries that id; otherwise one record is emitted per cluster per bucket.\n", "examples": ["cluster_abc123"]}}}]}, "BillingQuery": {"description": "Resolved query window and granularity (routes without a filter).", "allOf": [{"$ref": "#/components/schemas/BillingTimeRange"}, {"type": "object", "required": ["bucketSize"], "properties": {"bucketSize": {"$ref": "#/components/schemas/BillingBucketSize"}}}]}, "PodBillingQuery": {"allOf": [{"$ref": "#/components/schemas/BillingQuery"}, {"type": "object", "properties": {"podId": {"type": ["string", "null"], "description": "The podId filter applied, if any."}}}]}, "ServerlessBillingQuery": {"allOf": [{"$ref": "#/components/schemas/BillingQuery"}, {"type": "object", "properties": {"serverlessId": {"type": ["string", "null"], "description": "The serverlessId filter applied, if any."}}}]}, "NetworkVolumeBillingQuery": {"allOf": [{"$ref": "#/components/schemas/BillingQuery"}, {"type": "object", "properties": {"networkVolumeId": {"type": ["string", "null"], "description": "The networkVolumeId filter applied, if any."}}}]}, "ClusterBillingQuery": {"allOf": [{"$ref": "#/components/schemas/BillingQuery"}, {"type": "object", "properties": {"clusterId": {"type": ["string", "null"], "description": "The clusterId filter applied, if any."}}}]}, "BillingMetadata": {"type": "object", "required": ["query", "recordCount", "totals"], "properties": {"query": {"$ref": "#/components/schemas/BillingQuery"}, "recordCount": {"type": "integer", "description": "Number of records returned."}, "totals": {"$ref": "#/components/schemas/BillingAmounts"}}}, "PodBillingMetadata": {"type": "object", "required": ["query", "recordCount", "uniquePodCount", "totals"], "properties": {"query": {"$ref": "#/components/schemas/PodBillingQuery"}, "recordCount": {"type": "integer", "description": "Number of records returned (buckets times distinct pods)."}, "uniquePodCount": {"type": "integer", "description": "Number of distinct pods the records span."}, "totals": {"$ref": "#/components/schemas/PodBillingAmounts"}}}, "ServerlessBillingMetadata": {"type": "object", "required": ["query", "recordCount", "uniqueServerlessCount", "totals"], "properties": {"query": {"$ref": "#/components/schemas/ServerlessBillingQuery"}, "recordCount": {"type": "integer", "description": "Number of records returned (buckets times distinct endpoints)."}, "uniqueServerlessCount": {"type": "integer", "description": "Number of distinct serverless endpoints the records span."}, "totals": {"$ref": "#/components/schemas/ServerlessBillingAmounts"}}}, "EndpointBillingMetadata": {"type": "object", "required": ["query", "recordCount", "totals"], "properties": {"query": {"$ref": "#/components/schemas/BillingQuery"}, "recordCount": {"type": "integer"}, "totals": {"$ref": "#/components/schemas/EndpointBillingAmounts"}}}, "NetworkVolumeBillingMetadata": {"type": "object", "required": ["query", "recordCount", "uniqueNetworkVolumeCount", "totals"], "properties": {"query": {"$ref": "#/components/schemas/NetworkVolumeBillingQuery"}, "recordCount": {"type": "integer", "description": "Number of records returned (buckets times distinct volumes)."}, "uniqueNetworkVolumeCount": {"type": "integer", "description": "Number of distinct network volumes the records span."}, "totals": {"$ref": "#/components/schemas/NetworkVolumeBillingAmounts"}}}, "ClusterBillingMetadata": {"type": "object", "required": ["query", "recordCount", "uniqueClusterCount", "totals"], "properties": {"query": {"$ref": "#/components/schemas/ClusterBillingQuery"}, "recordCount": {"type": "integer", "description": "Number of records returned (buckets times distinct clusters)."}, "uniqueClusterCount": {"type": "integer", "description": "Number of distinct clusters the records span."}, "totals": {"$ref": "#/components/schemas/ClusterBillingAmounts"}}}, "ListBillingResponse": {"type": "object", "description": "Aggregated billing records across all Runpod resources.", "required": ["records", "metadata"], "properties": {"records": {"type": "array", "items": {"$ref": "#/components/schemas/BillingRecord"}}, "metadata": {"$ref": "#/components/schemas/BillingMetadata"}}}, "ListPodBillingResponse": {"type": "object", "description": "Billing records for pods.", "required": ["records", "metadata"], "properties": {"records": {"type": "array", "items": {"$ref": "#/components/schemas/PodBillingRecord"}}, "metadata": {"$ref": "#/components/schemas/PodBillingMetadata"}}}, "ListServerlessBillingResponse": {"type": "object", "description": "Billing records for serverless.", "required": ["records", "metadata"], "properties": {"records": {"type": "array", "items": {"$ref": "#/components/schemas/ServerlessBillingRecord"}}, "metadata": {"$ref": "#/components/schemas/ServerlessBillingMetadata"}}}, "ListEndpointBillingResponse": {"type": "object", "description": "Time-bucketed Runpod public endpoint billing records plus metadata for the resolved query, record count, and total endpoint amount.\n", "required": ["records", "metadata"], "properties": {"records": {"type": "array", "items": {"$ref": "#/components/schemas/EndpointBillingRecord"}}, "metadata": {"$ref": "#/components/schemas/EndpointBillingMetadata"}}}, "ListNetworkVolumeBillingResponse": {"type": "object", "description": "Time-bucketed network volume billing records plus metadata for the resolved query, record count, distinct volume count, and storage totals.\n", "required": ["records", "metadata"], "properties": {"records": {"type": "array", "items": {"$ref": "#/components/schemas/NetworkVolumeBillingRecord"}}, "metadata": {"$ref": "#/components/schemas/NetworkVolumeBillingMetadata"}}}, "ListClusterBillingResponse": {"type": "object", "description": "Time-bucketed Cluster billing records plus metadata for the resolved query, record count, distinct cluster count, and compute totals.\n", "required": ["records", "metadata"], "properties": {"records": {"type": "array", "items": {"$ref": "#/components/schemas/ClusterBillingRecord"}}, "metadata": {"$ref": "#/components/schemas/ClusterBillingMetadata"}}}, "ErrorResponse": {"type": "object", "required": ["title", "status", "detail"], "properties": {"title": {"type": "string", "description": "Short human-readable summary", "examples": ["Not Found"]}, "status": {"type": "integer", "description": "HTTP status code", "examples": [404]}, "detail": {"type": "string", "description": "Human-readable explanation", "examples": ["pod not found"]}, "errors": {"type": "array", "description": "Individual request-validation failures.", "items": {"type": "string"}, "examples": [["$: additional properties 'bogus' not allowed"]]}}}, "RateLimitHeader": {"type": "string", "description": "Live per-window quota state. Optional — omitted for rate-limit-exempt\ncallers.\n\nA structured-field list with one member per window (`minute`, `hour`,\n`day`), each carrying the remaining request count `r` and seconds until\nthe window resets `t`. Returned on responses to authenticated requests,\nnot only on 429s.\n", "examples": ["\"minute\";r=0;t=12, \"hour\";r=2800;t=1812, \"day\";r=49500;t=45012"]}, "RateLimitPolicyHeader": {"type": "string", "description": "Static per-window quota policy. Optional — omitted for rate-limit-exempt\ncallers.\n\nA structured-field list with one member per window (`minute`, `hour`,\n`day`), each carrying the quota `q` and the window length in seconds `w`.\nReturned on responses to authenticated requests, not only on 429s.\n", "examples": ["\"minute\";q=60;w=60, \"hour\";q=3000;w=3600, \"day\";q=50000;w=86400"]}}}, "paths": {"/v2/account/ssh-keys": {"get": {"operationId": "getSshKeys", "summary": "List registered SSH public keys", "description": "Returns the account's registered SSH public keys — the keys provisioned into pods created with `startSsh` and used to authenticate the SSH connections reported in a pod's `ssh` block.", "tags": ["Account"], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SshKeys"}, "examples": {"keys": {"summary": "Successful response", "value": {"keys": ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILXGDN/SclOozk1xsDztpmhGiKkkrfQB9SKoO8dSIQQZ me@example.com"]}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "put": {"operationId": "updateSshKeys", "summary": "Replace registered SSH public keys", "description": "Replaces the account's full set of registered SSH public keys. Existing keys not present in the request are removed; send `[]` to remove all keys. Keys take effect for pods created afterwards with `startSsh` — running pods are not updated.", "tags": ["Account"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateSshKeysRequest"}, "examples": {"replaceKeys": {"summary": "Register a single key", "value": {"keys": ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILXGDN/SclOozk1xsDztpmhGiKkkrfQB9SKoO8dSIQQZ me@example.com"]}}}}}}, "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK — the updated key set", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SshKeys"}, "examples": {"keys": {"summary": "Successful response", "value": {"keys": ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILXGDN/SclOozk1xsDztpmhGiKkkrfQB9SKoO8dSIQQZ me@example.com"]}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "422": {"$ref": "#/components/responses/UnprocessableEntityError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/pods": {"get": {"operationId": "listPods", "summary": "List pods", "description": "Returns pods owned by the authenticated user. Cluster member\npods are excluded by default; set `includeClusterPods=true` to include\nthem (each carries a non-null `cluster` membership block).\n", "tags": ["Pods"], "parameters": [{"name": "includeClusterPods", "in": "query", "required": false, "description": "Include cluster member pods in the result. Defaults to false.", "schema": {"type": "boolean", "default": false}, "example": false}], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListPodsResponse"}, "examples": {"pods": {"summary": "Successful response", "value": {"pods": [{"id": "7h9k2m4n6p", "name": "pytorch-training", "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "args": "", "disk": 50, "ports": ["8888/http", "22/tcp"], "env": {"MODEL_NAME": "llama-3"}, "registry": null, "status": "RUNNING", "actions": ["stop", "restart", "terminate"], "mounts": {"persistent": {"size": 20, "path": "/workspace"}}, "gpu": {"id": "NVIDIA GeForce RTX 4090", "count": 1}, "cloud": "SECURE", "dataCenterId": "US-KS-2", "cudaVersion": "12.8", "ssh": {"proxy": {"host": "ssh.runpod.io", "port": 22, "username": "7h9k2m4n6p-64411eb2", "command": "ssh 7h9k2m4n6p-64411eb2@ssh.runpod.io"}, "direct": {"host": "195.26.233.3", "port": 34446, "username": "root", "command": "ssh root@195.26.233.3 -p 34446"}}, "template": "9x4m2p7v", "cost": 0.44, "locked": false, "globalNetworking": {"enabled": false}, "runtime": {"uptime": 3600, "ports": [{"private": 22, "public": 34446, "type": "tcp", "ip": "195.26.233.3"}]}, "createdAt": "2026-06-01T12:00:00Z", "startedAt": "2026-06-01T12:02:00Z"}]}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "post": {"operationId": "createPod", "summary": "Create a pod", "description": "Creates a new pod. `name` is always required; supply exactly one of\n`gpu` or `cpu` to select compute (a GPU or a CPU pod). Container\nsettings come from the body, from a template referenced by\n`templateId` (body fields override the template's), or both; `image`\nis required unless `templateId` is set. See `CreatePodRequest` for\nthe full body.\n\nReturns `201` with the created pod. Provisioning is asynchronous: the\npod starts in `PROVISIONING`, transitions through `STARTING`, and\nreaches `RUNNING` once its container is healthy. Poll `getPod` (or\nwatch the pod's `status`) to observe readiness rather than assuming\nthe pod is running when this call returns.\n\n## Checking what you can deploy\n\nThis endpoint places one specific GPU type. It does not search for\ncapacity, and it does not fall back to a different GPU. To find out\nwhat is deployable before you call it, read the catalog:\n\n- [List GPU types](https://docs.runpod.io/api-reference-v2/catalog/list-gpu-types)\n — GPU types with pricing, per-cloud ceilings, and, with\n `include=AVAILABILITY&product=POD`, current pod stock.\n- [List data centers](https://docs.runpod.io/api-reference-v2/catalog/list-data-centers)\n — locations, with `include=GPU_AVAILABILITY` for stock per data\n center.\n\nBoth accept filters that combine, so you can narrow by location and by\ncompute in one request — for example\n`GET /v2/catalog/datacenters?regions=EUROPE&include=GPU_AVAILABILITY`\nreturns only European data centers, each carrying the GPU types\ncurrently available there.\n\n## Deploying under region and GPU constraints\n\nIf you need a particular GPU in a particular geography, the working\npattern is read-then-create: narrow the catalog to an acceptable\n(data center, GPU) set, then call this endpoint once per candidate in\nyour order of preference until one returns `201`. The runnable sample\nalongside this operation does exactly that.\n\nAvailability can change between the catalog read and the create call,\nso treat the catalog as a way to order your candidates, not as a\nreservation — a create can still fail for capacity on a GPU the\ncatalog just reported as available.\n\nWhich failures are worth retrying:\n\n| Status | Meaning | Do |\n| --- | --- | --- |\n| `422` | The body does not match the contract. `errors` lists each violation. | Fix the request. Never retry. |\n| `400` | The body matches the contract but was rejected — either it breaks a cross-field rule, or this GPU and data center combination could not be placed. | Try your next candidate. |\n| `402` | Insufficient balance. | Stop; no candidate will succeed. |\n| `403` | Your account cannot access the requested pool. | Skip this candidate, keep going. |\n| `429` | Rate limited. | Back off using `Retry-After`, then resume. |\n| `5xx` | Transient upstream failure. | Retry the same candidate with backoff. |\n\n`400` covers both \"your request breaks a rule\" and \"no capacity\",\nbecause capacity exhaustion currently carries no machine-readable code\nof its own — only a human-readable `detail`. A rule violation is\ndeterministic, so it fails identically on every candidate: if *every*\ncandidate returns `400`, read the last `detail` as a problem with the\nrequest rather than as absent capacity.\n", "tags": ["Pods"], "x-codeSamples": [{"lang": "Python", "label": "Region-constrained deploy loop", "source": "import os\nimport time\n\nimport requests\n\nAPI = \"https://api.runpod.io\"\nSESSION = requests.Session()\nSESSION.headers[\"Authorization\"] = f\"Bearer {os.environ['RUNPOD_API_KEY']}\"\n\n# Most preferred GPU first. The loop stops at the first one that places.\nGPU_PREFERENCE = [\n \"NVIDIA GeForce RTX 4090\",\n \"NVIDIA GeForce RTX 5090\",\n \"NVIDIA H100 PCIe\",\n]\nUSABLE = {\"LOW\", \"MEDIUM\", \"HIGH\"} # anything but NONE\n\n\ndef candidates(region):\n \"\"\"(gpu_id, datacenter_id) pairs that the catalog reports as deployable,\n ordered by GPU_PREFERENCE then by descending stock.\"\"\"\n response = SESSION.get(\n f\"{API}/v2/catalog/datacenters\",\n params={\"regions\": region, \"include\": \"GPU_AVAILABILITY\"},\n timeout=30,\n )\n response.raise_for_status()\n\n rank = {\"HIGH\": 0, \"MEDIUM\": 1, \"LOW\": 2}\n found = []\n for datacenter in response.json()[\"dataCenters\"]:\n for gpu in datacenter.get(\"gpuAvailability\", []):\n if gpu[\"id\"] in GPU_PREFERENCE and gpu[\"availability\"] in USABLE:\n found.append((gpu[\"id\"], datacenter[\"id\"], gpu[\"availability\"]))\n\n found.sort(key=lambda c: (GPU_PREFERENCE.index(c[0]), rank[c[2]]))\n return [(gpu_id, dc_id) for gpu_id, dc_id, _ in found]\n\n\ndef create(gpu_id, datacenter_id):\n return SESSION.post(\n f\"{API}/v2/pods\",\n json={\n \"name\": \"inference-worker\",\n \"image\": \"runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404\",\n \"gpu\": {\"id\": gpu_id, \"count\": 1},\n \"dataCenterIds\": [datacenter_id],\n \"disk\": 50,\n },\n timeout=60,\n )\n\n\ndef create_with_backoff(gpu_id, datacenter_id, attempts=5):\n \"\"\"Rate limits and 5xx are not the candidate's fault, so they are\n retried in place rather than moving to the next GPU.\"\"\"\n for attempt in range(attempts):\n response = create(gpu_id, datacenter_id)\n if response.status_code == 429:\n # Retry-After is integer seconds on this API.\n time.sleep(int(response.headers.get(\"Retry-After\", 5)))\n continue\n if response.status_code >= 500:\n time.sleep(2**attempt)\n continue\n return response\n raise RuntimeError(f\"{attempts} transient failures for {gpu_id}; upstream unhealthy\")\n\n\ndef deploy(region=\"EUROPE\"):\n last_detail = None\n\n for gpu_id, datacenter_id in candidates(region):\n response = create_with_backoff(gpu_id, datacenter_id)\n\n if response.status_code == 201:\n return response.json()\n\n problem = response.json()\n last_detail = problem.get(\"detail\")\n\n if response.status_code == 422:\n # Contract violation — identical on every candidate.\n raise SystemExit(f\"Bad request: {problem.get('errors', last_detail)}\")\n if response.status_code == 402:\n raise SystemExit(f\"Cannot deploy: {last_detail}\")\n if response.status_code in (400, 403):\n # 403: no access to this pool. 400: rule violation, or this\n # GPU/data center could not be placed. Either way, move on.\n continue\n\n response.raise_for_status()\n\n # Every candidate was refused. A rule violation fails the same way on\n # all of them, so the last detail is the useful signal here.\n raise SystemExit(f\"No candidate placed in {region}. Last error: {last_detail}\")\n\n\nif __name__ == \"__main__\":\n pod = deploy()\n print(f\"{pod['id']} placed in {pod['dataCenterId']} on {pod['gpu']['id']}\")\n"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreatePodRequest"}, "examples": {"gpuPod": {"summary": "GPU pod", "value": {"name": "pytorch-training", "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "gpu": {"id": "NVIDIA GeForce RTX 4090", "count": 1}, "disk": 50}}}}}}, "responses": {"201": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Pod"}, "examples": {"pod": {"summary": "Successful response", "value": {"id": "7h9k2m4n6p", "name": "pytorch-training", "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "args": "", "disk": 50, "ports": ["8888/http", "22/tcp"], "env": {"MODEL_NAME": "llama-3"}, "registry": null, "status": "PROVISIONING", "actions": ["start", "terminate"], "mounts": {"persistent": {"size": 20, "path": "/workspace"}}, "gpu": {"id": "NVIDIA GeForce RTX 4090", "count": 1}, "cloud": "SECURE", "dataCenterId": "US-KS-2", "cudaVersion": "12.8", "ssh": {"proxy": {"host": "ssh.runpod.io", "port": 22, "username": "7h9k2m4n6p-64411eb2", "command": "ssh 7h9k2m4n6p-64411eb2@ssh.runpod.io"}, "direct": null}, "template": "9x4m2p7v", "cost": 0.44, "locked": false, "globalNetworking": {"enabled": false}, "runtime": {}, "createdAt": "2026-06-01T12:00:00Z", "startedAt": null}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "400": {"$ref": "#/components/responses/BadRequestError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "422": {"$ref": "#/components/responses/UnprocessableEntityError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/pods/{id}": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Pod identifier", "example": "pod_abc123"}], "get": {"operationId": "getPod", "summary": "Get a pod", "description": "Returns a single pod by ID.", "tags": ["Pods"], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Pod"}, "examples": {"pod": {"summary": "Successful response", "value": {"id": "7h9k2m4n6p", "name": "pytorch-training", "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "args": "", "disk": 50, "ports": ["8888/http", "22/tcp"], "env": {"MODEL_NAME": "llama-3"}, "registry": null, "status": "RUNNING", "actions": ["stop", "restart", "terminate"], "mounts": {"persistent": {"size": 20, "path": "/workspace"}}, "gpu": {"id": "NVIDIA GeForce RTX 4090", "count": 1}, "cloud": "SECURE", "dataCenterId": "US-KS-2", "cudaVersion": "12.8", "ssh": {"proxy": {"host": "ssh.runpod.io", "port": 22, "username": "7h9k2m4n6p-64411eb2", "command": "ssh 7h9k2m4n6p-64411eb2@ssh.runpod.io"}, "direct": {"host": "195.26.233.3", "port": 34446, "username": "root", "command": "ssh root@195.26.233.3 -p 34446"}}, "template": "9x4m2p7v", "cost": 0.44, "locked": false, "globalNetworking": {"enabled": false}, "runtime": {"uptime": 3600, "ports": [{"private": 22, "public": 34446, "type": "tcp", "ip": "195.26.233.3"}]}, "createdAt": "2026-06-01T12:00:00Z", "startedAt": "2026-06-01T12:02:00Z"}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "patch": {"operationId": "updatePod", "summary": "Update a pod", "description": "Partially updates a pod's configuration. This is a PATCH: only the\nfields present in the body are changed, and omitted fields are left\nuntouched. Use empty values only when you explicitly mean to clear a\nfield (for example, set `registry` to `null` or set `ports` to `[]`).\nSee `UpdatePodRequest` for the full body.\n\nMutable fields: `name`, `image`, `args`, `disk`, `ports`, `env`,\n`registry`, `mounts`, `locked`, and `globalNetworking`. Some changes\napply immediately while others (e.g. `globalNetworking`) take effect\non the pod's next start/restart, as noted on the individual fields.\n\nPods that belong to a Cluster cannot be updated here — manage them\nthrough `/v2/clusters/{id}`.\n\nReturns `200` with the full updated pod.\n", "tags": ["Pods"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdatePodRequest"}, "examples": {"renamePod": {"summary": "Rename pod", "value": {"name": "renamed-training-pod"}}}}}}, "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Pod"}, "examples": {"pod": {"summary": "Successful response", "value": {"id": "7h9k2m4n6p", "name": "renamed-training-pod", "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "args": "", "disk": 50, "ports": ["8888/http", "22/tcp"], "env": {"MODEL_NAME": "llama-3"}, "registry": null, "status": "RUNNING", "actions": ["stop", "restart", "terminate"], "mounts": {"persistent": {"size": 20, "path": "/workspace"}}, "gpu": {"id": "NVIDIA GeForce RTX 4090", "count": 1}, "cloud": "SECURE", "dataCenterId": "US-KS-2", "cudaVersion": "12.8", "ssh": {"proxy": {"host": "ssh.runpod.io", "port": 22, "username": "7h9k2m4n6p-64411eb2", "command": "ssh 7h9k2m4n6p-64411eb2@ssh.runpod.io"}, "direct": {"host": "195.26.233.3", "port": 34446, "username": "root", "command": "ssh root@195.26.233.3 -p 34446"}}, "template": "9x4m2p7v", "cost": 0.44, "locked": false, "globalNetworking": {"enabled": false}, "runtime": {"uptime": 3600, "ports": [{"private": 22, "public": 34446, "type": "tcp", "ip": "195.26.233.3"}]}, "createdAt": "2026-06-01T12:00:00Z", "startedAt": "2026-06-01T12:02:00Z"}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "400": {"$ref": "#/components/responses/BadRequestError"}, "409": {"description": "Pod belongs to a cluster and cannot be modified via the pod endpoints.", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "422": {"$ref": "#/components/responses/UnprocessableEntityError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "delete": {"operationId": "deletePod", "summary": "Terminate a pod", "description": "Permanently terminates and deletes a pod. This is irreversible:\ncompute is released, any `mounts.persistent` host-local storage is\ndestroyed with it (a `mounts.network` volume is only detached — the\nvolume itself is not deleted), and the pod no longer appears in\n`listPods`.\n\nPods that belong to a Cluster cannot be terminated here — delete the\ncluster via `DELETE /v2/clusters/{id}`.\n", "tags": ["Pods"], "responses": {"204": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Deleted. Response has no body."}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "409": {"description": "Pod belongs to a cluster and cannot be terminated via the pod endpoints.", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/pods/{id}/logs": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Pod identifier", "example": "pod_abc123"}], "get": {"operationId": "getPodLogs", "summary": "Stream pod logs", "description": "Streams pod logs as Server-Sent Events. The `source` query parameter\nselects which log source to include.\n\nThe SSE `data` payload shape is:\n`{ \"source\": \"container\", \"line\": \"...\", \"ts\": \"...\" }`.\nLog-event `id` values are the event `ts` timestamp so\nbrowser/EventSource reconnects can resume with `Last-Event-ID`.\n", "tags": ["Pods"], "parameters": [{"$ref": "#/components/parameters/LogSourceParam"}, {"$ref": "#/components/parameters/LogTail"}, {"$ref": "#/components/parameters/LogSince"}, {"$ref": "#/components/parameters/LogLastEventID"}], "responses": {"200": {"description": "Pod log event stream", "headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}, "Cache-Control": {"schema": {"type": "string"}, "description": "Always `no-cache` for SSE responses."}, "Connection": {"schema": {"type": "string"}, "description": "Always `keep-alive` to hold the SSE stream open."}, "X-Accel-Buffering": {"schema": {"type": "string"}, "description": "Always `no` to disable proxy buffering of the SSE stream."}}, "content": {"text/event-stream": {"schema": {"type": "string", "description": "Server-Sent Events stream. Each event includes an `id:` line and a JSON `data:` payload with `source`, `line`, and `ts` fields."}, "examples": {"logLine": {"summary": "Successful response", "value": "id: 2026-06-01T12:02:03Z/000000000001\ndata: {\"ts\":\"2026-06-01T12:02:03Z\",\"source\":\"container\",\"line\":\"Model loaded.\"}\n"}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/pods/{id}/action": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}, "example": "pod_abc123"}], "post": {"operationId": "podAction", "summary": "Trigger a pod state transition", "description": "Triggers a state transition on a pod. Send a JSON body with a single\n`action` field, e.g. `{ \"action\": \"stop\" }`.\n\nValid actions:\n- `start` — boot a stopped pod (`EXITED` or `ERROR`) back toward\n `RUNNING`.\n- `stop` — stop a running or provisioning pod, releasing GPU/CPU\n compute while keeping its disk. The pod moves to `EXITED`.\n- `restart` — restart a `RUNNING` pod's container in place.\n- `terminate` — permanently delete the pod and release its resources\n (equivalent to `deletePod`).\n\nWhich actions are valid depends on the pod's current status, and the\ncurrently permitted set is published in the pod's `actions` field:\n`RUNNING` allows `stop`/`restart`/`terminate`; `EXITED` and `ERROR`\nallow `start`/`terminate`; `PROVISIONING` and `STARTING` allow\n`stop`/`terminate`.\n\n`start`, `stop`, and `restart` return `200` with the updated pod.\n`terminate` returns `204` with no body. Requesting an action that is\nnot valid for the pod's current status returns `409`.\n", "tags": ["Pods"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/PodActionRequest"}, "examples": {"startPod": {"summary": "Start pod", "value": {"action": "start"}}}}}}, "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Action applied — returns updated pod", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Pod"}, "examples": {"pod": {"summary": "Successful response", "value": {"id": "7h9k2m4n6p", "name": "pytorch-training", "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "args": "", "disk": 50, "ports": ["8888/http", "22/tcp"], "env": {"MODEL_NAME": "llama-3"}, "registry": null, "status": "RUNNING", "actions": ["stop", "restart", "terminate"], "mounts": {"persistent": {"size": 20, "path": "/workspace"}}, "gpu": {"id": "NVIDIA GeForce RTX 4090", "count": 1}, "cloud": "SECURE", "dataCenterId": "US-KS-2", "cudaVersion": "12.8", "ssh": {"proxy": {"host": "ssh.runpod.io", "port": 22, "username": "7h9k2m4n6p-64411eb2", "command": "ssh 7h9k2m4n6p-64411eb2@ssh.runpod.io"}, "direct": {"host": "195.26.233.3", "port": 34446, "username": "root", "command": "ssh root@195.26.233.3 -p 34446"}}, "template": "9x4m2p7v", "cost": 0.44, "locked": false, "globalNetworking": {"enabled": false}, "runtime": {"uptime": 3600, "ports": [{"private": 22, "public": 34446, "type": "tcp", "ip": "195.26.233.3"}]}, "createdAt": "2026-06-01T12:00:00Z", "startedAt": "2026-06-01T12:02:00Z"}}}}}}, "204": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Only returned when `action=terminate`; response has no body."}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "409": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Action not valid for current pod status", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequestError"}, "422": {"$ref": "#/components/responses/UnprocessableEntityError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/clusters": {"get": {"operationId": "listClusters", "summary": "List clusters", "description": "Returns all clusters owned by the authenticated user.", "tags": ["Clusters"], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListClustersResponse"}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "post": {"operationId": "createCluster", "summary": "Create a cluster", "description": "Creates a multi-node cluster. `compute` sets the homogeneous\npod shape; the container configuration applies to every pod and can be spread\nfrom a template response.\n", "tags": ["Clusters"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateClusterRequest"}}}}, "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Cluster"}}}}, "400": {"$ref": "#/components/responses/BadRequestError"}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "422": {"$ref": "#/components/responses/UnprocessableEntityError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/clusters/{id}": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Cluster identifier", "example": "cluster_abc123"}], "get": {"operationId": "getCluster", "summary": "Get a cluster", "description": "Returns a single cluster by ID. The pods field is an aggregate summary (total + count by status); fetch the member pods themselves from /v2/clusters/{id}/pods.", "tags": ["Clusters"], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Cluster"}}}}, "404": {"description": "Cluster not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "patch": {"operationId": "updateCluster", "summary": "Rename a cluster", "description": "Renames a cluster. This endpoint only changes the cluster\nname — compute shape, type, and container configuration are fixed at\ncreation and cannot be updated.\n", "tags": ["Clusters"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateClusterRequest"}}}}, "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Cluster"}}}}, "404": {"description": "Cluster not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "400": {"$ref": "#/components/responses/BadRequestError"}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "422": {"$ref": "#/components/responses/UnprocessableEntityError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "delete": {"operationId": "deleteCluster", "summary": "Delete a cluster", "description": "Permanently deletes a cluster and terminates all of its member pods.", "tags": ["Clusters"], "responses": {"204": {"description": "Deleted"}, "404": {"description": "Cluster not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/clusters/{id}/pods": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Cluster identifier", "example": "cluster_abc123"}], "get": {"operationId": "listClusterPods", "summary": "List a cluster's pods", "description": "Returns the full member pods of a cluster. The cluster summary (`GET /v2/clusters/{id}`) carries only aggregate pod counts; this endpoint returns each member as a complete Pod object.", "tags": ["Clusters"], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListPodsResponse"}}}}, "404": {"description": "Cluster not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/serverless": {"get": {"operationId": "listEndpoints", "summary": "List serverless endpoints", "description": "Returns all serverless endpoints owned by the authenticated user.", "tags": ["Serverless"], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListEndpointsResponse"}, "examples": {"endpoints": {"summary": "Successful response", "value": {"endpoints": [{"id": "4m7x2k9q", "name": "image-generator", "type": "QUEUE", "requestUrls": {"run": "https://api.runpod.ai/v2/4m7x2k9q/run", "runSync": "https://api.runpod.ai/v2/4m7x2k9q/runsync", "status": "https://api.runpod.ai/v2/4m7x2k9q/status/{job_id}", "stream": "https://api.runpod.ai/v2/4m7x2k9q/stream/{job_id}", "cancel": "https://api.runpod.ai/v2/4m7x2k9q/cancel/{job_id}", "retry": "https://api.runpod.ai/v2/4m7x2k9q/retry/{job_id}", "purgeQueue": "https://api.runpod.ai/v2/4m7x2k9q/purge-queue", "health": "https://api.runpod.ai/v2/4m7x2k9q/health"}, "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "args": "", "disk": 20, "ports": ["8000/http"], "env": {"MODEL_NAME": "sdxl"}, "registry": null, "gpu": {"pools": ["ADA_24"], "count": 1, "allowedCudaVersions": [], "minCudaVersion": null}, "workers": {"min": 0, "max": 5, "idleTimeout": 5}, "scaling": {"type": "QUEUE_DELAY", "queueDelay": 4}, "dataCenterIds": ["US-KS-2"], "networkVolumes": ["2q9m7x4c"], "timeout": 300000, "flashboot": "OFF", "createdAt": "2026-06-01T12:00:00Z"}]}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "post": {"operationId": "createEndpoint", "summary": "Create a serverless endpoint", "description": "Creates a serverless endpoint. Callers specify exactly one of `gpu` or\n`cpu`; neither or both returns 400. Container settings come from the\nbody, from a serverless template referenced by `templateId` (body\nfields override the template's), or both; `image` is required unless\n`templateId` is set. See `CreateEndpointRequest` for the full body.\n\nThe CUDA constraints live on `gpu` — `gpu.allowedCudaVersions` and\n`gpu.minCudaVersion` — so a CPU create cannot express them and the\nschema rejects the attempt with a 422. A non-empty set and a floor are\nmutually exclusive (400 if both are sent); an explicit empty set states\nno constraint and may accompany a floor.\n\nReturns `201` with the created endpoint. The endpoint can accept jobs\nimmediately, but starts with no active workers unless `workers.min`\nis greater than 0. Workers are provisioned on demand and autoscaled\nbetween `workers.min` and `workers.max` according to the `scaling`\npolicy, so the first request to an idle endpoint may incur cold-start\nlatency while a worker pulls its image and boots.\n\n## Checking what you can deploy\n\n`gpu.pools` takes serverless GPU **pool** IDs, not the GPU type IDs\nused for pods. `gpu.excludedTypes` takes the type IDs — it subtracts\nspecific cards from the pools you picked. Read both from the catalog\nbefore you create:\n\n- [List GPU types](https://docs.runpod.io/api-reference-v2/catalog/list-gpu-types)\n — the `pool` field carries the pool ID for each GPU type (`null`\n means that type is not in a serverless pool). Add\n `include=AVAILABILITY&product=SERVERLESS` for current serverless\n stock.\n- [List data centers](https://docs.runpod.io/api-reference-v2/catalog/list-data-centers)\n — locations to constrain with `dataCenterIds`, with\n `include=GPU_AVAILABILITY` for stock per data center.\n\nUnlike pod creation, you do not need to retry across GPUs yourself:\nlist every pool you are willing to run on and workers are placed on\nwhichever one has capacity. Listing more pools — and leaving\n`dataCenterIds` unset — gives the scheduler more room and reduces the\nchance of workers failing to start when a single pool is exhausted.\n\nIf your workload needs a specific card, pick the pool that holds it and\nexclude the rest of that pool with `gpu.excludedTypes`. Keep at least\none type in the selection — upstream rejects a selection that leaves\nnone.\n", "tags": ["Serverless"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateEndpointRequest"}, "examples": {"serverlessEndpoint": {"summary": "Serverless GPU endpoint", "value": {"name": "image-generator", "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "type": "QUEUE", "gpu": {"pools": ["ADA_24"], "count": 1}, "workers": {"min": 0, "max": 5, "idleTimeout": 5}, "scaling": {"type": "QUEUE_DELAY", "queueDelay": 4}, "dataCenterIds": ["US-KS-2"], "timeout": 300000}}, "cpuServerlessEndpoint": {"summary": "Serverless CPU endpoint with multiple configurations", "value": {"name": "cpu-inference", "image": "python:3.11-slim", "type": "QUEUE", "cpu": [{"id": "cpu5c", "vcpuCount": 4}, {"id": "cpu5g", "vcpuCount": 8}], "workers": {"min": 0, "max": 3, "idleTimeout": 10}, "scaling": {"type": "QUEUE_DELAY", "queueDelay": 4}, "timeout": 300000}}}}}}, "responses": {"201": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Endpoint"}, "examples": {"endpoint": {"summary": "Successful response", "value": {"id": "4m7x2k9q", "name": "image-generator", "type": "QUEUE", "requestUrls": {"run": "https://api.runpod.ai/v2/4m7x2k9q/run", "runSync": "https://api.runpod.ai/v2/4m7x2k9q/runsync", "status": "https://api.runpod.ai/v2/4m7x2k9q/status/{job_id}", "stream": "https://api.runpod.ai/v2/4m7x2k9q/stream/{job_id}", "cancel": "https://api.runpod.ai/v2/4m7x2k9q/cancel/{job_id}", "retry": "https://api.runpod.ai/v2/4m7x2k9q/retry/{job_id}", "purgeQueue": "https://api.runpod.ai/v2/4m7x2k9q/purge-queue", "health": "https://api.runpod.ai/v2/4m7x2k9q/health"}, "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "args": "", "disk": 20, "ports": ["8000/http"], "env": {"MODEL_NAME": "sdxl"}, "registry": null, "gpu": {"pools": ["ADA_24"], "count": 1, "allowedCudaVersions": [], "minCudaVersion": null}, "workers": {"min": 0, "max": 5, "idleTimeout": 5}, "scaling": {"type": "QUEUE_DELAY", "queueDelay": 4}, "dataCenterIds": ["US-KS-2"], "networkVolumes": ["2q9m7x4c"], "timeout": 300000, "flashboot": "OFF", "createdAt": "2026-06-01T12:00:00Z"}}, "cpuEndpoint": {"summary": "Successful response for a CPU endpoint", "value": {"id": "7c3v1n8p", "name": "cpu-inference", "type": "QUEUE", "requestUrls": {"run": "https://api.runpod.ai/v2/7c3v1n8p/run", "runSync": "https://api.runpod.ai/v2/7c3v1n8p/runsync", "status": "https://api.runpod.ai/v2/7c3v1n8p/status/{job_id}", "stream": "https://api.runpod.ai/v2/7c3v1n8p/stream/{job_id}", "cancel": "https://api.runpod.ai/v2/7c3v1n8p/cancel/{job_id}", "retry": "https://api.runpod.ai/v2/7c3v1n8p/retry/{job_id}", "purgeQueue": "https://api.runpod.ai/v2/7c3v1n8p/purge-queue", "health": "https://api.runpod.ai/v2/7c3v1n8p/health"}, "image": "python:3.11-slim", "args": "", "disk": 20, "ports": [], "env": {}, "registry": null, "cpu": [{"id": "cpu5c", "vcpuCount": 4, "memory": 16}, {"id": "cpu5g", "vcpuCount": 8, "memory": 16}], "workers": {"min": 0, "max": 3, "idleTimeout": 10}, "scaling": {"type": "QUEUE_DELAY", "queueDelay": 4}, "dataCenterIds": [], "networkVolumes": [], "timeout": 300000, "flashboot": "OFF", "createdAt": "2026-06-01T12:00:00Z"}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "400": {"$ref": "#/components/responses/BadRequestError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "422": {"$ref": "#/components/responses/UnprocessableEntityError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/serverless/{id}": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Serverless endpoint identifier", "example": "ep_abc123"}], "get": {"operationId": "getEndpoint", "summary": "Get a serverless endpoint", "description": "Returns a single serverless endpoint by ID.", "tags": ["Serverless"], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Endpoint"}, "examples": {"endpoint": {"summary": "Successful response", "value": {"id": "4m7x2k9q", "name": "image-generator", "type": "LOAD_BALANCER", "requestUrls": {"base": "https://4m7x2k9q.api.runpod.ai", "health": "https://4m7x2k9q.api.runpod.ai/ping"}, "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "args": "", "disk": 20, "ports": ["8000/http"], "env": {"MODEL_NAME": "sdxl"}, "registry": null, "gpu": {"pools": ["ADA_24"], "count": 1, "allowedCudaVersions": [], "minCudaVersion": null}, "workers": {"min": 0, "max": 5, "idleTimeout": 5}, "scaling": {"type": "REQUEST_COUNT", "requestCount": 4}, "dataCenterIds": ["US-KS-2"], "networkVolumes": ["2q9m7x4c"], "timeout": 300000, "flashboot": "OFF", "createdAt": "2026-06-01T12:00:00Z"}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "patch": {"operationId": "updateEndpoint", "summary": "Update a serverless endpoint", "description": "Partially updates a serverless endpoint. This is a PATCH: only the\nfields present in the body are changed; omitted fields are left\nuntouched. See `UpdateEndpointRequest` for the full body.\n\nMutable fields: `name`, `gpu`, `cpu`, `workers` (`min`/`max`),\n`scaling` (`type`/`value`/`idleTimeout`), `dataCenterIds`,\n`networkVolumes`, `timeout`, `flashboot`, and the container settings\n(`image`, `args`, `disk`, `ports`, `env`, `registry`).\n\nOmitted compute preserves the current selection. `cpu` completely\nreplaces a CPU endpoint's selection; compute family is immutable.\n`gpu` on CPU, `cpu` on GPU, or both fields returns 400.\n\nReturns `200` with the full updated endpoint. Effect timing differs\nby field: scaling and worker-bound settings (`workers`, `scaling`,\n`timeout`) are applied to the autoscaler promptly, while\ncontainer-affecting changes (e.g. `image`, `env`) create a new\nendpoint release that rolls out as workers cycle — in-flight workers\nkeep the previous version until they are replaced. Track rollout via\n`listEndpointReleases`.\n", "tags": ["Serverless"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateEndpointRequest"}, "examples": {"scaleEndpoint": {"summary": "Scale endpoint", "value": {"workers": {"min": 1, "max": 10, "idleTimeout": 10}, "scaling": {"type": "QUEUE_DELAY", "queueDelay": 8}}}}}}}, "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Endpoint"}, "examples": {"endpoint": {"summary": "Successful response", "value": {"id": "4m7x2k9q", "name": "image-generator", "type": "QUEUE", "requestUrls": {"run": "https://api.runpod.ai/v2/4m7x2k9q/run", "runSync": "https://api.runpod.ai/v2/4m7x2k9q/runsync", "status": "https://api.runpod.ai/v2/4m7x2k9q/status/{job_id}", "stream": "https://api.runpod.ai/v2/4m7x2k9q/stream/{job_id}", "cancel": "https://api.runpod.ai/v2/4m7x2k9q/cancel/{job_id}", "retry": "https://api.runpod.ai/v2/4m7x2k9q/retry/{job_id}", "purgeQueue": "https://api.runpod.ai/v2/4m7x2k9q/purge-queue", "health": "https://api.runpod.ai/v2/4m7x2k9q/health"}, "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "args": "", "disk": 20, "ports": ["8000/http"], "env": {"MODEL_NAME": "sdxl"}, "registry": null, "gpu": {"pools": ["ADA_24"], "count": 1, "allowedCudaVersions": [], "minCudaVersion": null}, "workers": {"min": 1, "max": 10, "idleTimeout": 10}, "scaling": {"type": "QUEUE_DELAY", "queueDelay": 8}, "dataCenterIds": ["US-KS-2"], "networkVolumes": ["2q9m7x4c"], "timeout": 300000, "flashboot": "OFF", "createdAt": "2026-06-01T12:00:00Z"}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "400": {"$ref": "#/components/responses/BadRequestError"}, "422": {"$ref": "#/components/responses/UnprocessableEntityError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "delete": {"operationId": "deleteEndpoint", "summary": "Delete a serverless endpoint", "description": "Permanently deletes a serverless endpoint and its bound template.\nThis is irreversible: all workers are terminated and any queued or\nin-progress jobs are cancelled.\n", "tags": ["Serverless"], "responses": {"204": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Deleted. Response has no body."}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/serverless/{id}/workers": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Serverless endpoint identifier", "example": "ep_abc123"}], "get": {"operationId": "listEndpointWorkers", "summary": "List serverless endpoint workers", "description": "Lists the active workers for a serverless endpoint.\n\n**Returns.** A `200` with a `ListEndpointWorkersResponse`: a\n`workers` array (one entry per active worker, each carrying its `id`,\n`status`, and runtime details) plus a `summary` of worker counts\ngrouped by status. Only currently active workers are included;\nscaled-down workers are not returned.\n\n**How `status` is determined.** Each worker's `status` is derived by\nreconciling the worker pod's lifecycle status with the endpoint's\nlive job-queue view (which workers are actively serving requests).\nWhen the job-queue view is unavailable, the response degrades\ngracefully: the shape is unchanged, but each `status` and the summary\ncounts fall back to pod lifecycle alone.\n", "tags": ["Serverless"], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListEndpointWorkersResponse"}, "examples": {"workers": {"summary": "Successful response", "value": {"endpointVersion": 4, "summary": {"running": 1, "idle": 1, "initializing": 0, "throttled": 0, "unhealthy": 0, "total": 2}, "workers": [{"id": "8g3n5t6r", "status": "RUNNING", "isStale": false, "version": 4, "gpuCount": 1, "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "uptimeSeconds": 3600, "gpuTypeId": "NVIDIA GeForce RTX 4090", "dataCenterId": "US-KS-2", "startedAt": "2026-06-01T12:05:00Z"}]}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/serverless/{id}/releases": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Serverless endpoint identifier", "example": "ep_abc123"}], "get": {"operationId": "listEndpointReleases", "summary": "List serverless endpoint releases", "description": "Returns the endpoint's release history (newest first) plus a rollout\nsummary of how many workers are running the current version. Each\nrelease is a versioned configuration snapshot with a `diff` of what\nchanged; build-driven releases carry a `buildId` (fetch build detail via\nthe builds sub-routes).\n", "tags": ["Serverless"], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListEndpointReleasesResponse"}, "examples": {"releases": {"summary": "Successful response", "value": {"endpointVersion": 4, "rollout": {"inProgress": true, "workersOnLatest": 1, "workersTotal": 2, "percentOnLatest": 50}, "releases": [{"id": "5r9x2m7q", "version": 4, "source": "MANUAL", "buildId": null, "createdByUserId": null, "workerCount": 2, "createdAt": "2026-06-01T12:10:00Z", "diff": [{"field": "workers.max", "old": 5, "new": 10}]}]}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/serverless/{id}/workers/{workerId}/logs": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Serverless endpoint identifier", "example": "ep_abc123"}, {"name": "workerId", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Worker identifier (from GET /v2/serverless/{id}/workers)", "example": "worker_abc"}], "get": {"operationId": "getWorkerLogs", "summary": "Stream serverless worker logs", "description": "Streams a serverless worker's logs as Server-Sent Events. The `source`\nquery parameter selects which log source to include.\n\nThe SSE `data` payload shape is:\n`{ \"source\": \"container\", \"line\": \"...\", \"ts\": \"...\" }`.\nLog-event `id` values are the event `ts` timestamp so browser/EventSource\nreconnects can resume with `Last-Event-ID`.\n", "tags": ["Serverless"], "parameters": [{"$ref": "#/components/parameters/LogSourceParam"}, {"$ref": "#/components/parameters/LogTail"}, {"$ref": "#/components/parameters/LogSince"}, {"$ref": "#/components/parameters/LogLastEventID"}], "responses": {"200": {"description": "Worker log event stream", "headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}, "Cache-Control": {"schema": {"type": "string"}, "description": "Always `no-cache` for SSE responses."}, "Connection": {"schema": {"type": "string"}, "description": "Always `keep-alive` to hold the SSE stream open."}, "X-Accel-Buffering": {"schema": {"type": "string"}, "description": "Always `no` to disable proxy buffering of the SSE stream."}}, "content": {"text/event-stream": {"schema": {"type": "string", "description": "Server-Sent Events stream. Each event includes an `id:` line and a JSON `data:` payload with `source`, `line`, and `ts` fields."}, "examples": {"logLine": {"summary": "Successful response", "value": "id: 2026-06-01T12:05:04Z/000000000042\ndata: {\"ts\":\"2026-06-01T12:05:04Z\",\"source\":\"container\",\"line\":\"Worker ready.\"}\n"}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/templates": {"get": {"operationId": "listTemplates", "summary": "List templates", "description": "Returns all templates owned by the authenticated user.", "tags": ["Templates"], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListTemplatesResponse"}, "examples": {"templates": {"summary": "Successful response", "value": {"templates": [{"id": "9x4m2p7v", "name": "PyTorch GPU Template", "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "args": "", "disk": 50, "mounts": {"persistent": {"size": 20, "path": "/workspace"}}, "ports": ["8888/http"], "env": {"JUPYTER_ENABLE_LAB": "yes"}, "registry": null, "serverless": false, "public": false, "category": "NVIDIA", "startSsh": true, "startJupyter": false, "allowedCudaVersions": []}]}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "post": {"operationId": "createTemplate", "summary": "Create a template", "description": "Creates a reusable container-configuration preset — image, disk,\nports, env, registry, and mount settings — for pods and serverless\nendpoints. Pass its ID as `templateId` to `createPod` or\n`createEndpoint`, or spread its fields into the request body\ndirectly. Returns the created template.\n", "tags": ["Templates"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateTemplateRequest"}, "examples": {"podTemplate": {"summary": "Pod template", "value": {"name": "PyTorch GPU Template", "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "category": "NVIDIA", "disk": 50, "ports": ["8888/http"], "env": {"JUPYTER_ENABLE_LAB": "yes"}, "mounts": {"persistent": {"size": 20, "path": "/workspace"}}, "serverless": false, "public": false}}}}}}, "responses": {"201": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Template"}, "examples": {"template": {"summary": "Successful response", "value": {"id": "9x4m2p7v", "name": "PyTorch GPU Template", "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "args": "", "disk": 50, "mounts": {"persistent": {"size": 20, "path": "/workspace"}}, "ports": ["8888/http"], "env": {"JUPYTER_ENABLE_LAB": "yes"}, "registry": null, "serverless": false, "public": false, "category": "NVIDIA", "startSsh": true, "startJupyter": false, "allowedCudaVersions": []}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "400": {"$ref": "#/components/responses/BadRequestError"}, "422": {"$ref": "#/components/responses/UnprocessableEntityError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/templates/{id}": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}, "example": "tpl_abc"}], "get": {"operationId": "getTemplate", "summary": "Get a template", "description": "Returns the full configuration of a single template by ID. Serves\nboth templates you own and public catalog templates — everything you\ncan read. Updates and deletes remain restricted to templates you own.\n", "tags": ["Templates"], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Template"}, "examples": {"template": {"summary": "Successful response", "value": {"id": "9x4m2p7v", "name": "PyTorch GPU Template", "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "args": "", "disk": 50, "mounts": {"persistent": {"size": 20, "path": "/workspace"}}, "ports": ["8888/http"], "env": {"JUPYTER_ENABLE_LAB": "yes"}, "registry": null, "serverless": false, "public": false, "category": "NVIDIA", "startSsh": true, "startJupyter": false, "allowedCudaVersions": []}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "patch": {"operationId": "updateTemplate", "summary": "Update a template", "description": "Partially updates a template. This is a PATCH: only the fields\npresent in the body are changed; omitted fields are left untouched.\nSee `UpdateTemplateRequest` for the full body.\n\nMutable fields: `name`, `image`, `args`, `disk`, `ports`, `env`,\n`registry`, `mounts`, `serverless`, `public`, and `category`.\n\nOnly the template's owner can update it (authenticated via the\nrequest's API key); public catalog templates are readable via GET\nbut return `404` here. Returns `200` with the full updated template. Pods and\nendpoints already created from this template are not changed\nretroactively — the template is a snapshot applied at creation time.\n", "tags": ["Templates"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateTemplateRequest"}, "examples": {"renameTemplate": {"summary": "Rename template", "value": {"name": "Renamed PyTorch Template"}}}}}}, "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Template"}, "examples": {"template": {"summary": "Successful response", "value": {"id": "9x4m2p7v", "name": "Renamed PyTorch Template", "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "args": "", "disk": 50, "mounts": {"persistent": {"size": 20, "path": "/workspace"}}, "ports": ["8888/http"], "env": {"JUPYTER_ENABLE_LAB": "yes"}, "registry": null, "serverless": false, "public": false, "category": "NVIDIA", "startSsh": true, "startJupyter": false, "allowedCudaVersions": []}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "400": {"$ref": "#/components/responses/BadRequestError"}, "422": {"$ref": "#/components/responses/UnprocessableEntityError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "delete": {"operationId": "deleteTemplate", "summary": "Delete a template", "description": "Permanently deletes a template by ID. Only the template's owner can\ndelete it — public catalog templates return `404` here. Rejected if\nthe template is currently referenced by a pod (see that pod's\n`template` field) or bound to a serverless endpoint.\n", "tags": ["Templates"], "responses": {"204": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Deleted. Response has no body."}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "400": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Template is in use by a pod or serverless endpoint and cannot be deleted", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "404": {"$ref": "#/components/responses/NotFoundError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/network-volumes": {"get": {"operationId": "listNetworkVolumes", "summary": "List network volumes", "description": "Returns all network volumes owned by the authenticated user.", "tags": ["Network Volumes"], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListNetworkVolumesResponse"}, "examples": {"networkVolumes": {"summary": "Successful response", "value": {"networkVolumes": [{"id": "2q9m7x4c", "name": "training-dataset", "size": 100, "dataCenter": "US-KS-2", "type": "HIGH_PERFORMANCE"}]}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "post": {"operationId": "createNetworkVolume", "summary": "Create a network volume", "description": "Provisions a new network volume — persistent, network-attached\nstorage that can be mounted into pods and serverless workers.\nRequired inputs are `name`, `size` (in GB), and `dataCenter`; an\noptional `type` selects the storage tier and is immutable after\ncreation. See `CreateNetworkVolumeRequest` for the size bounds and\ntier options.\n\nThis creates a billable persistent resource that keeps incurring\nstorage charges until it is deleted. Returns `201` with the created\nnetwork volume, including its assigned `id`.\n", "tags": ["Network Volumes"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateNetworkVolumeRequest"}, "examples": {"networkVolume": {"summary": "Network volume", "value": {"name": "training-dataset", "dataCenter": "US-KS-2", "size": 50, "type": "HIGH_PERFORMANCE"}}}}}}, "responses": {"201": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/NetworkVolume"}, "examples": {"networkVolume": {"summary": "Successful response", "value": {"id": "2q9m7x4c", "name": "training-dataset", "size": 50, "dataCenter": "US-KS-2", "type": "HIGH_PERFORMANCE"}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "400": {"$ref": "#/components/responses/BadRequestError"}, "422": {"$ref": "#/components/responses/UnprocessableEntityError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/network-volumes/{id}": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}, "description": "Network volume identifier", "example": "agv6w2qcg7"}], "get": {"operationId": "getNetworkVolume", "summary": "Get a network volume", "description": "Returns a single network volume by ID.", "tags": ["Network Volumes"], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/NetworkVolume"}, "examples": {"networkVolume": {"summary": "Successful response", "value": {"id": "2q9m7x4c", "name": "training-dataset", "size": 100, "dataCenter": "US-KS-2", "type": "HIGH_PERFORMANCE"}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "patch": {"operationId": "updateNetworkVolume", "summary": "Update a network volume", "description": "Updates mutable fields on a network volume. Only provided fields are changed.\nNote: `size` may only increase; attempts to reduce size will be rejected.\n", "tags": ["Network Volumes"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateNetworkVolumeRequest"}, "examples": {"resizeNetworkVolume": {"summary": "Resize network volume", "value": {"size": 200}}}}}}, "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/NetworkVolume"}, "examples": {"networkVolume": {"summary": "Successful response", "value": {"id": "2q9m7x4c", "name": "training-dataset", "size": 200, "dataCenter": "US-KS-2", "type": "HIGH_PERFORMANCE"}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "400": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Invalid request body or size decrease attempted", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "404": {"$ref": "#/components/responses/NotFoundError"}, "422": {"$ref": "#/components/responses/UnprocessableEntityError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "delete": {"operationId": "deleteNetworkVolume", "summary": "Delete a network volume", "description": "Permanently deletes a network volume and releases its storage.", "tags": ["Network Volumes"], "responses": {"204": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Deleted. Response has no body."}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/registries": {"get": {"operationId": "listRegistries", "summary": "List container registries", "description": "Returns all container registry credentials owned by the authenticated user.", "tags": ["Registries"], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListRegistriesResponse"}, "examples": {"registries": {"summary": "Successful response", "value": {"registries": [{"id": "6n2k8v4d", "name": "dockerhub-private"}]}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "post": {"operationId": "createRegistry", "summary": "Create a container registry credential", "description": "Stores credentials for a private container registry. Credentials are write-only.", "tags": ["Registries"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateRegistryRequest"}, "examples": {"dockerHubRegistry": {"summary": "Docker Hub registry", "value": {"name": "dockerhub-private", "username": "runpod-user", "password": "correct-horse-battery-staple"}}}}}}, "responses": {"201": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Registry"}, "examples": {"registry": {"summary": "Successful response", "value": {"id": "6n2k8v4d", "name": "dockerhub-private"}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "400": {"$ref": "#/components/responses/BadRequestError"}, "422": {"$ref": "#/components/responses/UnprocessableEntityError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/registries/{id}": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}, "example": "reg_abc"}], "get": {"operationId": "getRegistry", "summary": "Get a container registry credential", "description": "Returns a single container registry credential by ID. `username` and\n`password` are never included in the response — credentials are\nwrite-only, matching `createRegistry`.\n", "tags": ["Registries"], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Registry"}, "examples": {"registry": {"summary": "Successful response", "value": {"id": "6n2k8v4d", "name": "dockerhub-private"}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "delete": {"operationId": "deleteRegistry", "summary": "Delete a container registry credential", "description": "Permanently deletes a container registry credential by ID. Rejected\nif any pod currently uses this credential to pull its image.\nTemplates that reference it are not part of that check — they\nsilently lose the reference (`registry` becomes null) instead of\nblocking the delete.\n", "tags": ["Registries"], "responses": {"204": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Deleted. Response has no body."}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "400": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Registry credential is in use by a pod and cannot be deleted", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "404": {"$ref": "#/components/responses/NotFoundError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/registries/delegations": {"get": {"operationId": "listDelegations", "summary": "List all ECR delegations", "tags": ["Registries"], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListDelegationsResponse"}}}}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}, "post": {"operationId": "createDelegation", "summary": "Register an ECR delegation", "tags": ["Registries"], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CreateDelegationRequest"}}}}, "responses": {"201": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Delegation created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EcrDelegation"}}}}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/registries/delegations/{id}": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}, "example": "deleg_abc"}], "delete": {"operationId": "revokeDelegation", "summary": "Revoke an ECR delegation", "tags": ["Registries"], "responses": {"204": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Delegation revoked"}, "404": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Delegation not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/catalog/gpus": {"get": {"operationId": "listGpuTypes", "summary": "List GPU types", "description": "Returns available GPU types with pricing. Availability is included only when requested with include=AVAILABILITY, which requires `product` — stock differs by product context. With countryCodes, the list is narrowed to GPU types deployable in those countries, so \"this geography + this chip\" resolves in one read.", "tags": ["Catalog"], "parameters": [{"$ref": "#/components/parameters/CatalogIncludeParam"}, {"$ref": "#/components/parameters/GpuProductFilter"}, {"$ref": "#/components/parameters/GpuCountFilter"}, {"$ref": "#/components/parameters/GpuCloudFilter"}, {"$ref": "#/components/parameters/CountryCodesFilter"}, {"$ref": "#/components/parameters/CudaVersionsFilter"}, {"$ref": "#/components/parameters/MinCudaVersionFilter"}], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListGpuTypesResponse"}, "examples": {"gpus": {"summary": "Successful response", "value": {"gpus": [{"id": "NVIDIA GeForce RTX 4090", "name": "RTX 4090", "pool": "ADA_24", "manufacturer": "NVIDIA", "memory": 24, "secure": true, "community": true, "price": {"secure": 0.44, "community": 0.31, "serverless": 1.1}, "maxCount": {"secure": 8, "community": 4}, "availability": "HIGH", "dataCenters": [{"id": "US-KS-2", "name": "US Kansas 2", "availability": "HIGH"}]}]}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/catalog/gpus/{id}": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}, "example": "NVIDIA GeForce RTX 4090"}], "get": {"operationId": "getGpuType", "summary": "Get a GPU type", "description": "Returns a single GPU type with pricing. Availability details are included only when requested with include=AVAILABILITY, which requires `product` — stock differs by product context.", "tags": ["Catalog"], "parameters": [{"$ref": "#/components/parameters/CatalogIncludeParam"}, {"$ref": "#/components/parameters/GpuProductFilter"}, {"$ref": "#/components/parameters/GpuCountFilter"}, {"$ref": "#/components/parameters/GpuCloudFilter"}, {"$ref": "#/components/parameters/CountryCodesFilter"}, {"$ref": "#/components/parameters/CudaVersionsFilter"}, {"$ref": "#/components/parameters/MinCudaVersionFilter"}], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GpuType"}, "examples": {"gpu": {"summary": "Successful response", "value": {"id": "NVIDIA GeForce RTX 4090", "name": "RTX 4090", "pool": "ADA_24", "manufacturer": "NVIDIA", "memory": 24, "secure": true, "community": true, "price": {"secure": 0.44, "community": 0.31, "serverless": 1.1}, "maxCount": {"secure": 8, "community": 4}, "availability": "HIGH", "dataCenters": [{"id": "US-KS-2", "name": "US Kansas 2", "availability": "HIGH"}]}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/catalog/cpus": {"get": {"operationId": "listCpuTypes", "summary": "List CPU types", "description": "Returns available CPU flavors. Availability is included only when requested with include=AVAILABILITY, which requires `product` — stock differs by product context.", "tags": ["Catalog"], "parameters": [{"$ref": "#/components/parameters/CatalogIncludeParam"}, {"$ref": "#/components/parameters/CpuProductFilter"}, {"$ref": "#/components/parameters/CpuVCPUCountFilter"}], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListCpuTypesResponse"}, "examples": {"cpus": {"summary": "Successful response", "value": {"cpus": [{"id": "cpu3c-2-4", "name": "Compute-Optimized", "group": "Gen 3", "vcpu": {"min": 2, "max": 32}, "ramGbPerVcpu": 2.5, "price": {"securePerVcpu": 0.04, "serverlessPerVcpu": 0.03}, "availability": "MEDIUM", "dataCenters": [{"id": "US-KS-2", "name": "US Kansas 2", "availability": "MEDIUM"}]}]}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/catalog/cpus/{id}": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}, "example": "cpu5c"}], "get": {"operationId": "getCpuType", "summary": "Get a CPU type", "description": "Returns a single CPU type with pricing. Availability details are included only when requested with include=AVAILABILITY, which requires `product` — stock differs by product context.", "tags": ["Catalog"], "parameters": [{"$ref": "#/components/parameters/CatalogIncludeParam"}, {"$ref": "#/components/parameters/CpuProductFilter"}, {"$ref": "#/components/parameters/CpuVCPUCountFilter"}], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CpuType"}, "examples": {"cpu": {"summary": "Successful response", "value": {"id": "cpu3c-2-4", "name": "Compute-Optimized", "group": "Gen 3", "vcpu": {"min": 2, "max": 32}, "ramGbPerVcpu": 2.5, "price": {"securePerVcpu": 0.04, "serverlessPerVcpu": 0.03}, "availability": "MEDIUM", "dataCenters": [{"id": "US-KS-2", "name": "US Kansas 2", "availability": "MEDIUM"}]}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/catalog/datacenters": {"get": {"operationId": "listDataCenters", "summary": "List data centers", "description": "Returns available data center locations with region, compliance, supported network volume tiers, and global networking support. Use include=GPU_AVAILABILITY or include=CPU_AVAILABILITY to add per-resource availability arrays to each data center. The regions, networkVolumeTypes, compliance, and globalNetwork query parameters filter the list before it is returned.\n", "tags": ["Catalog"], "parameters": [{"name": "include", "in": "query", "required": false, "description": "Comma-separated optional expansions. Supported value: GPU_AVAILABILITY, CPU_AVAILABILITY.", "style": "form", "explode": false, "schema": {"type": "array", "items": {"$ref": "#/components/schemas/DataCenterInclude"}, "example": ["GPU_AVAILABILITY"]}}, {"name": "regions", "in": "query", "required": false, "description": "Comma-separated DataCenterRegion enum values. Values within this filter use OR semantics. Different filter families combine with AND.", "style": "form", "explode": false, "schema": {"type": "array", "items": {"$ref": "#/components/schemas/DataCenterRegion"}, "example": ["EUROPE", "ASIA"]}}, {"name": "networkVolumeTypes", "in": "query", "required": false, "description": "Comma-separated volume types. Supported values: STANDARD, HIGH_PERFORMANCE. Values within this filter use AND semantics; volumes=STANDARD,HIGH_PERFORMANCE requires both storage types. Different filter families combine with AND.", "style": "form", "explode": false, "schema": {"type": "array", "items": {"$ref": "#/components/schemas/VolumeType"}, "example": ["STANDARD", "HIGH_PERFORMANCE"]}}, {"name": "compliance", "in": "query", "required": false, "description": "Comma-separated Compliance enum values. Values within this filter use AND semantics; compliance=GDPR,SOC_2_TYPE_2 requires both certifications. Different filter families combine with AND.", "style": "form", "explode": false, "schema": {"type": "array", "items": {"$ref": "#/components/schemas/Compliance"}, "example": ["GDPR", "SOC_2_TYPE_2"]}}, {"name": "globalNetwork", "in": "query", "required": false, "description": "Filter by global networking support. true returns only data centers that support global networking; false only those that do not. Different filter families combine with AND.", "schema": {"type": "boolean"}, "example": true}], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListDataCentersResponse"}, "examples": {"dataCenters": {"summary": "Successful response", "value": {"dataCenters": [{"id": "US-KS-2", "name": "US Kansas 2", "region": "NORTH_AMERICA", "globalNetwork": true, "networkVolumeTypes": ["STANDARD", "HIGH_PERFORMANCE"], "compliance": ["SOC_2_TYPE_2", "ISO_IEC_27001"], "gpuAvailability": [{"id": "NVIDIA GeForce RTX 4090", "name": "RTX 4090", "availability": "HIGH"}], "cpuAvailability": [{"id": "cpu3c-2-4", "name": "Compute-Optimized", "availability": "MEDIUM"}]}]}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/catalog/datacenters/{id}": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}, "example": "US-CA-2"}], "get": {"operationId": "getDataCenter", "summary": "Get a data center", "description": "Returns a single data center. Availability is included only when requested with include=GPU_AVAILABILITY or include=CPU_AVAILABILITY.", "tags": ["Catalog"], "parameters": [{"name": "include", "in": "query", "required": false, "description": "Comma-separated optional expansions. Supported value: GPU_AVAILABILITY, CPU_AVAILABILITY.", "style": "form", "explode": false, "schema": {"type": "array", "items": {"$ref": "#/components/schemas/DataCenterInclude"}, "example": ["GPU_AVAILABILITY"]}}], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DataCenter"}, "examples": {"dataCenter": {"summary": "Successful response", "value": {"id": "US-KS-2", "name": "US Kansas 2", "region": "NORTH_AMERICA", "globalNetwork": true, "networkVolumeTypes": ["STANDARD", "HIGH_PERFORMANCE"], "compliance": ["SOC_2_TYPE_2", "ISO_IEC_27001"], "gpuAvailability": [{"id": "NVIDIA GeForce RTX 4090", "name": "RTX 4090", "availability": "HIGH"}], "cpuAvailability": [{"id": "cpu3c-2-4", "name": "Compute-Optimized", "availability": "MEDIUM"}]}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "404": {"$ref": "#/components/responses/NotFoundError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/catalog/templates": {"get": {"operationId": "listPublicTemplates", "summary": "List public templates", "description": "Returns the public template catalog. `source` selects which slice:\n`official` (the default) is Runpod-curated templates, `verified` is\ncommunity templates Runpod has verified, and `community` is everything\nelse other users have shared publicly. Both pod and serverless\ntemplates appear — use each entry's `serverless` flag to tell them\napart. `registry` is always null for templates you don't own. Your own\ntemplates (public or private) are managed under `/v2/templates`; fetch\nany individual template — catalog or owned — via `/v2/templates/{id}`.\n\nAt most 100 templates are returned. Pagination is not yet supported.\n", "tags": ["Catalog"], "parameters": [{"name": "source", "in": "query", "required": false, "schema": {"type": "string", "enum": ["official", "verified", "community"], "default": "official"}, "description": "Which slice of the catalog to return: `official` for\nRunpod-curated templates (default), `verified` for\nRunpod-verified community templates, or `community` for all other\npublicly shared templates.\n", "example": "official"}], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListTemplatesResponse"}, "examples": {"templates": {"summary": "Successful response", "value": {"templates": [{"id": "30zmvf89kd", "name": "PyTorch 2.8", "image": "runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404", "args": "", "disk": 50, "mounts": {}, "ports": ["8888/http", "22/tcp"], "env": {}, "registry": null, "serverless": false, "public": true, "category": "NVIDIA", "startSsh": true, "startJupyter": true, "allowedCudaVersions": []}]}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/billing": {"get": {"operationId": "listBilling", "summary": "Get aggregated billing history", "description": "Returns time-bucketed total spend across all billable Runpod resources for the authenticated user. Use startTime/endTime with bucketSize for an explicit range, or lastN with bucketSize for the most recent buckets. Each record reports one bucket's total plus pod, serverless, storage, public endpoint, and Instant Cluster cost components. The metadata block echoes the resolved query window, record count, and totals across all returned buckets.\n", "tags": ["Billing"], "parameters": [{"$ref": "#/components/parameters/BillingStartTime"}, {"$ref": "#/components/parameters/BillingEndTime"}, {"$ref": "#/components/parameters/BillingBucketSize"}, {"$ref": "#/components/parameters/BillingLastN"}], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListBillingResponse"}, "examples": {"billing": {"summary": "Successful response", "value": {"records": [{"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-02T00:00:00Z", "totalAmount": 42.34, "podGpuAmount": 18.2, "podCpuAmount": 0, "podDiskAmount": 1.1, "serverlessGpuAmount": 12.6, "serverlessCpuAmount": 0, "serverlessDiskAmount": 0.44, "serverlessFeeAmount": 1.25, "storageStandardAmount": 0, "storageHighPerformanceAmount": 2.5, "endpointAmount": 3.21, "clusterGpuAmount": 2.5, "clusterDiskAmount": 0.3, "clusterNetworkingAmount": 0.24}], "metadata": {"query": {"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-02T00:00:00Z", "bucketSize": "day"}, "recordCount": 1, "totals": {"totalAmount": 42.34, "podGpuAmount": 18.2, "podCpuAmount": 0, "podDiskAmount": 1.1, "serverlessGpuAmount": 12.6, "serverlessCpuAmount": 0, "serverlessDiskAmount": 0.44, "serverlessFeeAmount": 1.25, "storageStandardAmount": 0, "storageHighPerformanceAmount": 2.5, "endpointAmount": 3.21, "clusterGpuAmount": 2.5, "clusterDiskAmount": 0.3, "clusterNetworkingAmount": 0.24}}}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/billing/pods": {"get": {"operationId": "listPodBilling", "summary": "Get pod billing history", "description": "Returns pod-only billing detail for the authenticated user, split into time buckets by startTime/endTime with bucketSize or by lastN recent buckets. Use podId to narrow the response to one GPU or CPU pod; without it, records are emitted per pod per bucket. Each record includes podId, GPU, CPU, disk, and total amounts, while metadata echoes the resolved query and totals across the pod records. Use listBilling when you need aggregate spend across every billable resource family.\n", "tags": ["Billing"], "parameters": [{"$ref": "#/components/parameters/BillingStartTime"}, {"$ref": "#/components/parameters/BillingEndTime"}, {"$ref": "#/components/parameters/BillingBucketSize"}, {"$ref": "#/components/parameters/BillingLastN"}, {"name": "podId", "in": "query", "required": false, "description": "Filter to a specific pod (GPU or CPU).", "schema": {"type": "string"}, "example": "pod_abc123"}], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListPodBillingResponse"}, "examples": {"podBilling": {"summary": "Successful response", "value": {"records": [{"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-02T00:00:00Z", "podId": "7h9k2m4n6p", "totalAmount": 12.34, "gpuAmount": 11.1, "cpuAmount": 0, "diskAmount": 1.24}], "metadata": {"query": {"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-02T00:00:00Z", "bucketSize": "day", "podId": "7h9k2m4n6p"}, "recordCount": 1, "totals": {"totalAmount": 12.34, "gpuAmount": 11.1, "cpuAmount": 0, "diskAmount": 1.24}, "uniquePodCount": 1}}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/billing/serverless": {"get": {"operationId": "listServerlessBilling", "summary": "Get serverless billing history", "description": "Returns serverless endpoint billing detail for the authenticated user, split into time buckets by startTime/endTime with bucketSize or by lastN recent buckets. Use serverlessId to filter to one endpoint; without it, records are emitted per serverless endpoint per bucket. Each record reports endpoint-level GPU, CPU, disk, platform fee, and total amounts. This is distinct from pod billing, which covers standalone GPU and CPU pod costs rather than serverless endpoint workloads.\n", "tags": ["Billing"], "parameters": [{"$ref": "#/components/parameters/BillingStartTime"}, {"$ref": "#/components/parameters/BillingEndTime"}, {"$ref": "#/components/parameters/BillingBucketSize"}, {"$ref": "#/components/parameters/BillingLastN"}, {"name": "serverlessId", "in": "query", "required": false, "description": "Filter to a specific serverless endpoint.", "schema": {"type": "string"}, "example": "jpnw0v75y3qoql"}], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListServerlessBillingResponse"}, "examples": {"serverlessBilling": {"summary": "Successful response", "value": {"records": [{"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-02T00:00:00Z", "serverlessId": "4m7x2k9q", "totalAmount": 8.9, "gpuAmount": 7.5, "cpuAmount": 0, "diskAmount": 0.4, "feeAmount": 1.0}], "metadata": {"query": {"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-02T00:00:00Z", "bucketSize": "day", "serverlessId": "4m7x2k9q"}, "recordCount": 1, "totals": {"totalAmount": 8.9, "gpuAmount": 7.5, "cpuAmount": 0, "diskAmount": 0.4, "feeAmount": 1.0}, "uniqueServerlessCount": 1}}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/billing/endpoints": {"get": {"operationId": "listEndpointBilling", "summary": "Get public endpoint billing history", "description": "Returns Runpod public endpoint billing history for the authenticated user, split into time buckets by startTime/endTime with bucketSize or by lastN recent buckets. Each record reports the endpoint total for one bucket, and metadata echoes the resolved query window, record count, and total endpoint amount across all returned records.\n", "tags": ["Billing"], "parameters": [{"$ref": "#/components/parameters/BillingStartTime"}, {"$ref": "#/components/parameters/BillingEndTime"}, {"$ref": "#/components/parameters/BillingBucketSize"}, {"$ref": "#/components/parameters/BillingLastN"}], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListEndpointBillingResponse"}, "examples": {"endpointBilling": {"summary": "Successful response", "value": {"records": [{"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-02T00:00:00Z", "totalAmount": 3.21}], "metadata": {"query": {"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-02T00:00:00Z", "bucketSize": "day"}, "recordCount": 1, "totals": {"totalAmount": 3.21}}}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/billing/network-volumes": {"get": {"operationId": "listNetworkVolumeBilling", "summary": "Get network volume billing history", "description": "Returns network volume billing history for the authenticated user, split into time buckets by startTime/endTime with bucketSize or by lastN recent buckets. Use networkVolumeId to filter to one volume; without it, records are emitted per volume per bucket. Each record includes standard storage, high-performance storage, and total amounts, while metadata reports the resolved query, distinct volume count, and totals across the returned records.\n", "tags": ["Billing"], "parameters": [{"$ref": "#/components/parameters/BillingStartTime"}, {"$ref": "#/components/parameters/BillingEndTime"}, {"$ref": "#/components/parameters/BillingBucketSize"}, {"$ref": "#/components/parameters/BillingLastN"}, {"name": "networkVolumeId", "in": "query", "required": false, "description": "Filter to a specific network volume.", "schema": {"type": "string"}, "example": "vol_abc123"}], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListNetworkVolumeBillingResponse"}, "examples": {"networkVolumeBilling": {"summary": "Successful response", "value": {"records": [{"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-02T00:00:00Z", "networkVolumeId": "2q9m7x4c", "totalAmount": 5.79, "standardAmount": 0, "highPerformanceAmount": 5.79}], "metadata": {"query": {"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-02T00:00:00Z", "bucketSize": "day", "networkVolumeId": "2q9m7x4c"}, "recordCount": 1, "totals": {"totalAmount": 5.79, "standardAmount": 0, "highPerformanceAmount": 5.79}, "uniqueNetworkVolumeCount": 1}}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}, "/v2/billing/clusters": {"get": {"operationId": "listClusterBilling", "summary": "Get cluster billing history", "description": "Returns Cluster billing history for the authenticated user, split into time buckets by startTime/endTime with bucketSize or by lastN recent buckets. Use clusterId to filter to one cluster; without it, records are emitted per cluster per bucket. Each record includes GPU compute, disk, inter-node networking, and total amounts. Clusters are GPU-only, so no CPU cost component is returned.\n", "tags": ["Billing"], "parameters": [{"$ref": "#/components/parameters/BillingStartTime"}, {"$ref": "#/components/parameters/BillingEndTime"}, {"$ref": "#/components/parameters/BillingBucketSize"}, {"$ref": "#/components/parameters/BillingLastN"}, {"name": "clusterId", "in": "query", "required": false, "description": "Filter to a specific cluster.", "schema": {"type": "string"}, "example": "cluster_abc123"}], "responses": {"200": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ListClusterBillingResponse"}, "examples": {"clusterBilling": {"summary": "Successful response", "value": {"records": [{"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-02T00:00:00Z", "clusterId": "5c2n8m4q", "totalAmount": 99.0, "gpuAmount": 95.0, "diskAmount": 3.0, "networkingAmount": 1.0}], "metadata": {"query": {"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-02T00:00:00Z", "bucketSize": "day", "clusterId": "5c2n8m4q"}, "recordCount": 1, "totals": {"totalAmount": 99.0, "gpuAmount": 95.0, "diskAmount": 3.0, "networkingAmount": 1.0}, "uniqueClusterCount": 1}}}}}}}, "401": {"$ref": "#/components/responses/UnauthorizedError"}, "403": {"$ref": "#/components/responses/ForbiddenError"}, "429": {"$ref": "#/components/responses/TooManyRequestsError"}, "default": {"headers": {"RateLimit": {"$ref": "#/components/headers/RateLimit"}, "RateLimit-Policy": {"$ref": "#/components/headers/RateLimit-Policy"}}, "description": "Error", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/ErrorResponse"}}}}}}}}}
|