Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: GPU Cloud Reservations API
description: 'REST API of GPUcloud.ca: GPU plans, GPU servers (deploy, power actions, metrics, firewall), SSH keys and API keys. All prices are in CAD. Authenticate with a REST API key: `Authorization: Bearer `. AI agents should use the MCP endpoint (https://gpucloud.ca/api/mcp) with an MCP key instead. REST keys (prefix gpu_) are created in the console, expire after 90 days and are either full access or read-only (GET only; a read-only key gets 401 on any other method). Write requests (POST, PUT, DELETE) must also send the header `Origin: https://gpucloud.ca`, otherwise they get 403. Developer guide: https://gpucloud.ca/en/developers'
version: 1.1.1
contact:
name: GPU Cloud Support
url: https://gpucloud.ca
email: info@gpucloud.ca
servers:
- url: https://gpucloud.ca/api
description: Production
security: []
tags:
- name: Reservations
paths:
/reservations:
get:
summary: List Reservations
description: GPU reservations of the authenticated user (status, place in the queue, end date, server launched).
operationId: listReservations
tags:
- Reservations
security:
- BearerAuth: []
responses:
'200':
description: Reservations, newest first
content:
application/json:
schema:
type: object
properties:
reservations:
type: array
items:
$ref: '#/components/schemas/Reservation'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalError'
post:
summary: Reserve a GPU
description: 'Reserve a GPU machine that is out of stock: GPU Cloud launches the server automatically as soon as it is back, before other customers (first come, first served per machine). A saved credit card is required (402 with error RESERVATION_CARD_REQUIRED and accountAction PAYMENT_REQUIRED carrying the card link), and the explicit authorization (consent). The automatic reload is not required: the answer carries onFundsExhausted, hibernationThresholdCad and, when the reload is off, autoReloadWarning. Nothing is charged when reserving; at launch, only the amount missing (first hour plus the hibernation threshold) is charged to the saved card.'
operationId: createReservation
tags:
- Reservations
security:
- BearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateReservationRequest'
example:
productId: gpu-h100-x8
sshKeyId: clxyz123456
maxHourlyCad: 25.0
validityDays: 7
acceptAlternative: false
consent: true
consentVersion: '2026-10-10'
consentLang: en
responses:
'201':
description: The reservation
content:
application/json:
schema:
type: object
properties:
reservation:
$ref: '#/components/schemas/Reservation'
onFundsExhausted:
type: string
enum:
- HIBERNATE
- DELETE
allowedOnFundsExhausted:
type: array
items:
type: string
enum:
- HIBERNATE
- DELETE
hibernationThresholdCad:
type: number
autoReloadEnabled:
type: boolean
onFundsExhaustedNote:
type: string
autoReloadWarning:
$ref: '#/components/schemas/AutoReloadWarning'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'402':
$ref: '#/components/responses/PaymentRequired'
'404':
$ref: '#/components/responses/NotFound'
'409':
description: Too many reservations waiting (5 at most)
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: RESERVATION_LIMIT_REACHED
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalError'
/reservations/{reservationId}:
parameters:
- name: reservationId
in: path
required: true
schema:
type: string
description: Reservation id
delete:
summary: Cancel a Reservation
description: 'Cancel a waiting reservation (nothing is charged). While a launch attempt runs, the answer is 202 CANCEL_REQUESTED: the attempt stops before any charge or launch not made yet.'
operationId: cancelReservation
tags:
- Reservations
security:
- BearerAuth: []
responses:
'200':
description: The reservation
content:
application/json:
schema:
type: object
properties:
reservation:
$ref: '#/components/schemas/Reservation'
'202':
description: The reservation
content:
application/json:
schema:
type: object
properties:
reservation:
$ref: '#/components/schemas/Reservation'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'409':
description: No longer waiting
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: RESERVATION_NOT_CANCELLABLE
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalError'
/reservations/{reservationId}/renew:
parameters:
- name: reservationId
in: path
required: true
schema:
type: string
description: Reservation id
post:
summary: Renew a Reservation
description: Renew a reservation for 1 to 30 days (7 by default). A waiting one keeps its place in the queue; an expired or payment-failed one goes back in the queue after the card check.
operationId: renewReservation
tags:
- Reservations
security:
- BearerAuth: []
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
validityDays:
type: integer
minimum: 1
maximum: 30
default: 7
example:
validityDays: 7
responses:
'200':
description: The reservation
content:
application/json:
schema:
type: object
properties:
reservation:
$ref: '#/components/schemas/Reservation'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'402':
$ref: '#/components/responses/PaymentRequired'
'404':
$ref: '#/components/responses/NotFound'
'409':
description: Not renewable
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: RESERVATION_NOT_RENEWABLE
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalError'
components:
schemas:
FundsExhaustedAction:
type: string
enum:
- HIBERNATE
- DELETE
default: HIBERNATE
description: 'What happens to this hourly server when the balance reaches its threshold and no automatic reload brings it back. HIBERNATE: hibernated (its GPU place is kept, hourly hibernation fee), restarted as soon as the balance is back above the threshold. DELETE: no hibernation fee; it keeps running while the balance pays its next hour, then it is taken out of service, and restarted as soon as the balance pays its next hour again. A server is never deleted while the account has credit left. When the balance covers only about 24 hours of what the account spends per hour, a first notice is sent while the servers still run, then two more about 24 hours and 1 hour before the deletion; a server is deleted with its data only once it is out of service (stopped or hibernated for lack of credit, or hibernated by the user for at least 72 hours), once the credit is exhausted (the balance no longer pays the next hour of the account''s servers), after the three notices and at least 24 hours after the first. Adding credits cancels the deletion. Machines that cannot be hibernated (spot) are always DELETE. Any other value: 400.'
Error:
type: object
properties:
error:
type: string
required:
- error
AccountAction:
type: object
description: What to do to fix an account or payment problem, with the direct absolute link. Same object on every route and in the MCP tool errors (structuredContent.error.accountAction). The message is in French when Accept-Language asks for it, otherwise in English.
properties:
code:
type: string
enum:
- NO_API_KEY
- INVALID_API_KEY
- PAYMENT_REQUIRED
- BUDGET_CAP_REACHED
description: Stable machine code. NO_API_KEY and INVALID_API_KEY come with HTTP 401, PAYMENT_REQUIRED and BUDGET_CAP_REACHED with HTTP 402.
message:
type: string
description: Clear sentence telling what to do, including the link.
action:
type: object
properties:
label:
type: string
url:
type: string
format: uri
required:
- label
- url
links:
type: object
description: 'Absolute links: account creation, sign in, API keys page, billing, add credits (opens the credit window), payment card, budget or cap setting, documentation.'
properties:
signup:
type: string
format: uri
login:
type: string
format: uri
apiKeys:
type: string
format: uri
billing:
type: string
format: uri
addCredits:
type: string
format: uri
paymentMethod:
type: string
format: uri
budget:
type: string
format: uri
documentation:
type: string
format: uri
required:
- signup
- login
- apiKeys
- billing
- addCredits
- paymentMethod
- budget
- documentation
minimumCad:
type: number
description: 'PAYMENT_REQUIRED only, when known: credits (CAD) covering one hour of the GPU asked for, computed by the server from the same price as the deployment.'
minimumTopupCad:
type: number
description: Smallest credit purchase accepted (CAD), given with minimumCad.
balanceCad:
type: number
description: 'PAYMENT_REQUIRED and BUDGET_CAP_REACHED, when known: the account''s credit balance (CAD) when the request was refused.'
hibernationThresholdCad:
type: number
description: 'PAYMENT_REQUIRED, when a server is concerned: its hibernation threshold (CAD), the larger of 3 CAD and 2 hours of its hourly rate. A running hourly server is hibernated when the balance reaches its threshold (after the automatic reload was tried); it restarts automatically as soon as the balance is above the threshold. A server is never deleted while the account has credit left. When the balance covers only about 24 hours of what the account spends per hour, a first notice is sent while the servers still run, then two more about 24 hours and 1 hour before the deletion; a server is deleted with its data only once it is out of service (stopped or hibernated for lack of credit, or hibernated by the user for at least 72 hours), once the credit is exhausted (the balance no longer pays the next hour of the account''s servers), after the three notices and at least 24 hours after the first. Adding credits cancels the deletion. For the restart of such a server, minimumCad is the balance that restarts it (threshold + 0.01).'
capCad:
type: number
description: 'BUDGET_CAP_REACHED of an MCP key, for a money cap: the cap reached (CAD). The cap set by the customer is always respected: nothing is charged or reloaded beyond it.'
capRemainingCad:
type: number
description: 'BUDGET_CAP_REACHED of an MCP key, with capCad: what is left of that cap (CAD).'
required:
- code
- message
- action
- links
AutoReloadWarning:
type:
- object
- 'null'
description: 'Present only when the automatic reload is OFF: show the message to the user. Never a payment link.'
properties:
code:
type: string
enum:
- AUTO_RELOAD_OFF
action:
type: string
enum:
- HIBERNATE
- DELETE
thresholdCad:
type: number
description: 'Threshold of the server (CAD): the larger of 3 CAD and 2 hours of its rate.'
message:
type: string
example: Without automatic reload, this server will be hibernated when your balance reaches $3.00 (its threshold). It will be deleted only if your credit runs out, after three e-mail notices. For an overnight job, turn on the automatic reload.
autoReloadSettingsUrl:
type: string
format: uri
description: Console page where the automatic reload is turned on.
Reservation:
type: object
description: 'A GPU reservation: GPU Cloud launches the server automatically as soon as the machine is back in stock (first come, first served per machine).'
properties:
id:
type: string
productId:
type: string
description: Exact machine reserved (model and size).
productName:
type: string
status:
type: string
enum:
- ACTIVE
- PROCESSING
- FULFILLED
- PAYMENT_FAILED
- EXPIRED
- CANCELLED
maxHourlyCad:
type: number
description: Highest hourly price accepted (CAD). Above it at launch time, the reservation waits.
acceptAlternative:
type: boolean
templateId:
type:
- string
- 'null'
templateModel:
type:
- string
- 'null'
name:
type:
- string
- 'null'
expiresAt:
type: string
format: date-time
createdAt:
type: string
format: date-time
queuePosition:
type:
- integer
- 'null'
description: Place in the queue of this machine (1 = next) while waiting.
waitingReason:
type:
- string
- 'null'
description: PRICE_ABOVE_MAX, BUDGET_LIMIT_REACHED, KEY_CAP_REACHED, SETUP_REQUIRED or SSH_KEY_MISSING while it waits for that reason.
cancelRequested:
type: boolean
serverId:
type:
- string
- 'null'
description: Server launched for it (FULFILLED).
fulfilledProductId:
type:
- string
- 'null'
fulfilledAt:
type:
- string
- 'null'
format: date-time
source:
type: string
enum:
- console
- api
- mcp
onFundsExhausted:
type: string
enum:
- HIBERNATE
- DELETE
description: Action at the threshold of the server this reservation launches.
AccountActionError:
type: object
description: 'Error of an account or payment problem. Backward compatible: `error` keeps its previous string value (for example "Unauthorized" or "INSUFFICIENT_CREDITS"), `message` and the existing details stay; `accountAction` is added.'
properties:
error:
type: string
description: Previous error string or code, unchanged (backward compatibility).
message:
type: string
requiredCredits:
type: number
description: 'INSUFFICIENT_CREDITS: credits (CAD) the action needs.'
currentBalance:
type: number
accountAction:
$ref: '#/components/schemas/AccountAction'
required:
- error
- accountAction
CreateReservationRequest:
type: object
required:
- productId
- sshKeyId
- maxHourlyCad
- consent
- consentVersion
properties:
productId:
type: string
description: Exact GPU machine (model and size), e.g. gpu-h100-x8.
sshKeyId:
type: string
maxHourlyCad:
type: number
description: 'Highest hourly price accepted (CAD): at least the current price, at most 5 times it.'
validityDays:
type: integer
minimum: 1
maximum: 30
default: 7
acceptAlternative:
type: boolean
default: false
description: Launch an equivalent machine (same usage, at least the same GPU memory, never spot) when the exact one is not in stock.
name:
type: string
description: 'Server name: letters, digits, space, dot, dash, underscore (63 at most).'
templateId:
type: string
templateModel:
type: string
consent:
type: boolean
description: 'The user explicitly agreed: "I authorize GPU Cloud to launch this server as soon as it is available, to charge my saved card the amount needed if my balance is not enough, then to bill it by the hour under the terms."'
enum:
- true
consentVersion:
type: string
example: '2026-10-10'
consentLang:
type: string
enum:
- fr
- en
onFundsExhausted:
$ref: '#/components/schemas/FundsExhaustedAction'
responses:
PaymentRequired:
description: 'Payment required (accountAction.code PAYMENT_REQUIRED: not enough credit, no saved card or a declined card) or a budget cap reached (BUDGET_CAP_REACHED: account or server budget limit, nothing charged). accountAction.balanceCad gives the balance and, when a server is concerned, accountAction.hibernationThresholdCad its hibernation threshold (a server is hibernated when the balance reaches it and restarts as soon as the balance is above it; it is deleted only once the account''s credit is exhausted, after three notices). Add your card and credits at accountAction.action.url (or raise the cap), then send the same request again.'
content:
application/json:
schema:
$ref: '#/components/schemas/AccountActionError'
examples:
insufficientCredits:
summary: Not enough credit to deploy
value:
error: INSUFFICIENT_CREDITS
message: Payment required. You need a paid order or at least enough credits for 1 hour of usage.
requiredCredits: 1.55
currentBalance: 0
accountAction:
code: PAYMENT_REQUIRED
message: 'Payment required. Add your card and credits here, then run the same request again: you will get your GPU. https://gpucloud.ca/en/console/billing?addCredits=25 At least 1.55 CAD is needed to cover one hour of this GPU (smallest credit purchase: 25 CAD).'
action:
label: Add a card and credits
url: https://gpucloud.ca/en/console/billing?addCredits=25
links:
signup: https://gpucloud.ca/en/auth/register
login: https://gpucloud.ca/en/auth/login
apiKeys: https://gpucloud.ca/en/console/settings#api-keys
billing: https://gpucloud.ca/en/console/billing
addCredits: https://gpucloud.ca/en/console/billing?addCredits=25
paymentMethod: https://gpucloud.ca/en/console/billing?addCredits=25#payment-method
budget: https://gpucloud.ca/en/console/billing#budget-limit
documentation: https://gpucloud.ca/en/developers#errors
minimumCad: 1.55
minimumTopupCad: 25
budgetCap:
summary: Account budget limit reached
value:
error: BUDGET_LIMIT_REACHED
message: The monthly budget limit of this account is reached.
scope: account
accountAction:
code: BUDGET_CAP_REACHED
message: 'The budget limit of this account was reached: nothing was charged. The account owner can raise or remove this limit here, then run the same request again: https://gpucloud.ca/en/console/billing#budget-limit'
action:
label: Change the limit
url: https://gpucloud.ca/en/console/billing#budget-limit
links:
signup: https://gpucloud.ca/en/auth/register
login: https://gpucloud.ca/en/auth/login
apiKeys: https://gpucloud.ca/en/console/settings#api-keys
billing: https://gpucloud.ca/en/console/billing
addCredits: https://gpucloud.ca/en/console/billing?addCredits=25
paymentMethod: https://gpucloud.ca/en/console/billing?addCredits=25#payment-method
budget: https://gpucloud.ca/en/console/billing#budget-limit
documentation: https://gpucloud.ca/en/developers#errors
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: Server not found
TooManyRequests:
description: Rate limit exceeded
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: Too many requests
Unauthorized:
description: 'No API key (accountAction.code NO_API_KEY) or an invalid, expired, revoked or read only key on a write (INVALID_API_KEY). Provide a valid API key as `Authorization: Bearer <key>`; accountAction gives the links to create an account and a key.'
headers:
WWW-Authenticate:
schema:
type: string
description: Bearer realm="gpucloud" (error="invalid_token" when a key was sent).
content:
application/json:
schema:
$ref: '#/components/schemas/AccountActionError'
examples:
noKey:
summary: No key sent
value:
error: Unauthorized. Use Bearer API key.
message: 'No API key was sent. Create a GPU Cloud account (https://gpucloud.ca/en/auth/register), then an API key in the console (https://gpucloud.ca/en/console/settings#api-keys), and send it in the header Authorization: Bearer gpu_...'
accountAction:
code: NO_API_KEY
message: 'No API key was sent. Create a GPU Cloud account (https://gpucloud.ca/en/auth/register), then an API key in the console (https://gpucloud.ca/en/console/settings#api-keys), and send it in the header Authorization: Bearer gpu_...'
action:
label: Create an account
url: https://gpucloud.ca/en/auth/register
links:
signup: https://gpucloud.ca/en/auth/register
login: https://gpucloud.ca/en/auth/login
apiKeys: https://gpucloud.ca/en/console/settings#api-keys
billing: https://gpucloud.ca/en/console/billing
addCredits: https://gpucloud.ca/en/console/billing?addCredits=25
paymentMethod: https://gpucloud.ca/en/console/billing?addCredits=25#payment-method
budget: https://gpucloud.ca/en/console/billing#budget-limit
documentation: https://gpucloud.ca/en/developers#errors
invalidKey:
summary: Invalid, expired or revoked key
value:
error: Unauthorized
message: 'This API key is invalid, expired, revoked or lacks the required permission. Create a new API key in the console (https://gpucloud.ca/en/console/settings#api-keys) and send it in the header Authorization: Bearer gpu_... No account yet: https://gpucloud.ca/en/auth/register'
accountAction:
code: INVALID_API_KEY
message: 'This API key is invalid, expired, revoked or lacks the required permission. Create a new API key in the console (https://gpucloud.ca/en/console/settings#api-keys) and send it in the header Authorization: Bearer gpu_... No account yet: https://gpucloud.ca/en/auth/register'
action:
label: Create an API key
url: https://gpucloud.ca/en/console/settings#api-keys
links:
signup: https://gpucloud.ca/en/auth/register
login: https://gpucloud.ca/en/auth/login
apiKeys: https://gpucloud.ca/en/console/settings#api-keys
billing: https://gpucloud.ca/en/console/billing
addCredits: https://gpucloud.ca/en/console/billing?addCredits=25
paymentMethod: https://gpucloud.ca/en/console/billing?addCredits=25#payment-method
budget: https://gpucloud.ca/en/console/billing#budget-limit
documentation: https://gpucloud.ca/en/developers#errors
BadRequest:
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: Invalid input
InternalError:
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: Internal server error
securitySchemes:
BearerAuth:
type: http
scheme: bearer
description: 'REST API key (prefix gpu_) created in the GPU Cloud console (Settings). Pass it as `Authorization: Bearer <your-api-key>`. Keys expire after 90 days; a read-only key may only call GET. Write requests (POST, PUT, DELETE) must also send `Origin: https://gpucloud.ca`.'