HTTP API for provisioning virtual servers, managing server operations and retrieving usage. Requests use bearer authentication. Request and response bodies use JSON.
Base URLhttps://enterprise.chartvps.com/v1
Versionv1.0.0
Endpoints24
AuthenticationBearer token
FormatJSON, UTF-8
01Getting started
Use the Partner API to manage virtual servers, SSH keys and backups, receive events, and retrieve usage. All endpoints use the base URL shown above, including /v1.
1. Obtain access and verify your key
Open API keys in your Enterprise dashboard and request API access. After approval, create a key and copy its value. Up to five keys can be active per account. If your account requires approved source IP addresses, ask your account contact to approve the integration server's outbound IP address before testing.
The cURL examples run in Bash or zsh. Set API_KEY and API_BASE_URL in your terminal; these are example environment variables. Requests send the key in the Authorization header.
# Replace YOUR_API_KEY with the complete key shown at creation.
export API_KEY='YOUR_API_KEY'
export API_BASE_URL='https://enterprise.chartvps.com/v1'
curl --silent --show-error --include "$API_BASE_URL/me" \
--header "Authorization: Bearer $API_KEY"
Expect 200 OK with your account, limits and key details. 401 means the key or access approval is invalid; 403 NETWORK_RESTRICTED means the request's source IP is not approved. Keep these variables set in the same terminal for the examples below.
2. Select your configuration
for resource in plans regions images; do
curl --silent --show-error "$API_BASE_URL/$resource" \
--header "Authorization: Bearer $API_KEY"
printf '\n'
done
Select code values returned for your account. An empty plan list means no plans are currently available to order. Register your SSH public key, then use the returned ssh_key.id in ssh_keys. Send the complete public key; keep its private key on your own machine.
3. Save and validate a request
Create server.json with the command below, then edit it to use your selected catalog codes and registered SSH key ID. The sample values are illustrative. dry_run: true validates the configuration and returns pricing without creating or charging for a server.
Expect 200 OK with valid: true and pricing. A dry run does not reserve capacity or guarantee that a later creation request will be accepted.
4. Create and track the server
When ready to provision a billable server, edit server.json to set dry_run to false. Generate an idempotency key once with uuidgen (or your application's UUID generator), and retain it with the final request body. Run the key-generation command only for a new intended server.
export IDEMPOTENCY_KEY="$(uuidgen)"
# Reuse the same key and unchanged file if this request must be retried.
curl --silent --show-error --include --request POST "$API_BASE_URL/servers" \
--header "Authorization: Bearer $API_KEY" \
--header "Idempotency-Key: $IDEMPOTENCY_KEY" \
--header "Content-Type: application/json" \
--data @server.json
Expect 202 Accepted. Copy server.id from the response and poll its URL, or use events to track provisioning.
active means provisioning completed; ssh_reachable_at records a successful TCP connection to port 22, which does not confirm SSH authentication or application readiness. Handle failed by inspecting failure and related events.
Examples use sample IDs, keys and prices. Replace them with values from your account. Requests to the production URL affect real resources.
02Authentication and limits
Send the API key in the Authorization header using the Bearer scheme. API keys belong to one partner account and authorize operations on that account's resources. API access must remain approved.
Authorization: Bearer <API_KEY>
Keys are displayed once when created. Store them securely on the server that runs your integration. Revoke a compromised or unused key from the dashboard. Invalid or revoked keys, and accounts without approved API access, receive 401 UNAUTHENTICATED.
The API specification and standalone reference do not require an API key. All operations below require authentication.
Concurrency and quotas
GET /v1/me returns inflight, servers and limits. Provisioning above the concurrent request limit returns 429 INFLIGHT_LIMIT; exceeding the server quota returns 403 QUOTA.
Request limits per account
Limits are shared across the account's API keys.
Scope
Requests per minute
All operations except server creation, combined
600
Server creation, including dry runs and replays
60
Password reset, within the general limit
20
Operating system rebuild, within the general limit
20
A rate-limited response returns 429 RATE_LIMITED. Wait at least the number of seconds specified by Retry-After. Adding API keys does not increase the account's limits.
03Requests and responses
Content types
Send JSON request bodies with Content-Type: application/json. Responses with a body use JSON. 204 No Content and 304 Not Modified responses have no body.
Identifiers and timestamps
Server IDs are strings prefixed with srv_. Account, SSH key, task, backup and event IDs are integers. Server, event and usage timestamps use ISO 8601 UTC. Invoice dates and daily usage dates use YYYY-MM-DD. Billing month parameters use YYYY-MM. Monetary amounts are decimal strings; use decimal arithmetic when processing them. The API does not return a currency code or billing timezone; use the currency and timezone confirmed for your account.
Pagination
GET /v1/servers and GET /v1/events accept limit (default 50, maximum 100) and after. Pass a non-null next_after from the previous response as the next request's after. A null cursor ends the result set. Server cursors are strings; event cursors are integers. Other list endpoints do not use these parameters.
Conditional requests
Server list and detail responses include an ETag and a private cache lifetime of five seconds. Send If-None-Match with that ETag to receive 304 when the representation is unchanged.
Idempotency
POST /v1/servers requires a non-empty Idempotency-Key of at most 128 characters, except when dry_run is true. Use one key per intended server and retain it with the original request body for 24 hours.
Once the result is saved, a retry with the same key and body returns that response with Idempotent-Replayed: true. Generated passwords are redacted on replay. Reusing a key with a different body returns 409 IDEMPOTENCY_MISMATCH.
A concurrent retry, or a request whose result could not be saved, returns 409 CONFLICT with details.reason: request_in_progress and Retry-After. Retry with the same key. If the conflict persists, provide support with details.server_id and the request ID.
After an ambiguous creation response, poll the server or repeat the original request with the same key. A server in requested can still be reconciled with the compute platform. Do not generate a new key while the outcome is unresolved.
Retry policy
For 429 or 503, respect Retry-After when present and apply exponential backoff with jitter. Some dependency failures omit this header; start with a short delay and increase it on repeated failures. The idempotency guarantee applies only to server creation. Do not automatically repeat password resets, rebuilds, backup requests or webhook configuration changes after a timeout; first establish whether the operation was accepted. A replay returns the originally stored response; retrieve the server separately for its current status. After the 24-hour retention period, resolve the original outcome before submitting another creation request.
04Server lifecycle and operations
Server creation and deletion return a server resource with 202 Accepted. Monitor that resource through GET /v1/servers/{id} or events. Server actions and backup operations return a task; poll GET /v1/tasks/{id} when task.id is non-null.
A task status of done means success; failed or canceled is unsuccessful. pending and running are incomplete. Treat unfamiliar statuses as unresolved. Poll at intervals of five seconds or longer. If no task ID is returned, poll the server and events for a rebuild, or the server's backup list for a backup. A password reset returns the new password; verify access to the guest. 202 alone does not confirm completion. The task's action may use platform names such as vm-restart instead of the submitted reboot.
Server status
Meaning
requested
Creation accepted; provisioning outcome is pending.
Creation failed. Inspect failure and related events.
Deletion protection
Set locked to true to prevent API deletion. This setting does not prevent a rebuild or backup restore.
Backup availability
Check backups.enabled in the plan and server responses. Backup creation and restore require backup support for that plan and configured storage. When backups are disabled or the plan configuration is missing, these operations return 403 FORBIDDEN with details.reason=backups_disabled before submission. Existing backups remain visible, and deleting a server still removes its backups.
Rebuild and restore
A rebuild reinstalls the selected operating system on the existing server. A restore replaces its disk contents with a selected backup. Both operations overwrite data. The server ID and assigned address remain associated with the existing server.
A failed rebuild can return the server to active. Check the task result and server.rebuild_failed event before treating a state change as success. Provisioning time depends on the selected image and available capacity.
Guest configuration
Images with cloud_init: true accept user_data beginning with #cloud-config or #!, up to 65,536 UTF-8 bytes after line-ending normalization. Avoid embedding persistent credentials. IPv4 is allocated in this API version; ipv6 remains null.
05Usage and billing
The account's assigned price book determines available plans, prices and discount rules. Retrieve the catalog before submitting a request. Use the prices returned for your account.
Usage is measured in started hours and capped per server per calendar month. Use the returned monthly_cap_hours rather than assuming a cap. Deletion stops billing at destroy_requested_at. Failed provisioning attempts are not billed; suspended and rebuilding servers remain billable.
Billing start
For vm_months_per_plan, billing starts at creation acceptance. For allocated_per_plan and allocated_combined, billing starts at active_at. The applicable discount_basis is returned with pricing data where available.
Discount basis
vm_months_per_plan selects discounts from monthly usage on each plan. allocated_per_plan counts qualifying allocated servers on each plan; allocated_combined counts them across the price book. Allocation-based rates apply to each started hour at the qualifying count for that hour. Later changes do not reprice recorded charges.
Use current_tier for the current allocation-based rate and period_segments for recorded rate intervals when present. GET /v1/usage returns monthly charges; GET /v1/servers/{id}/usage returns server usage.
Estimates
GET /v1/billing/estimate separates month-to-date charges from projected month-end charges and the next invoice. Projections assume the current fleet remains allocated and are not final invoice amounts.
06Errors
API errors use an error object. Branch on error.code; display error.message as a human-readable explanation. Optional error.details contains field errors or operation-specific information. Field errors are keyed directly by field name.
HTTP status
Error code
Meaning
400
VALIDATION, BAD_REQUEST
Malformed JSON or missing request requirements.
401
UNAUTHENTICATED
Invalid credentials or API access not approved.
402
CREDIT_LIMIT
Account credit limit reached.
403
NETWORK_RESTRICTED
The request source is outside the deployment's approved IP networks.
403
FROZEN, PARTNER_SUSPENDED, QUOTA
Account state or server quota prevents creation.
404
NOT_FOUND
The resource does not exist or is not owned by this account.
409
CONFLICT
Resource state or a concurrent update prevents the operation. Inspect details.reason.
409
IDEMPOTENCY_MISMATCH
Idempotency key reused with a different request body.
422
VALIDATION
Invalid parameters or rejected configuration.
429
RATE_LIMITED, INFLIGHT_LIMIT
Request rate or provisioning concurrency exceeded.
{
"error": {
"code": "VALIDATION",
"message": "Invalid request",
"details": {
"name": ["name must be an RFC 1123 hostname (lowercase letters, digits, hyphens, dots)"]
}
}
}
Record the HTTP status, error.code and X-Request-Id for troubleshooting. Include the request ID when contacting support. Do not log API keys or generated passwords.
07Webhooks
Configure an HTTPS destination with PUT /v1/webhook. Each delivery is a JSON event with id, type, at, server_id and data. The same events are available through GET /v1/events.
Verify the signature against the original request body bytes before parsing JSON or processing the event. Reject signatures more than five minutes from the current time. Use a constant-time comparison.
Event type header
X-Partner-Event
Signature header
X-Partner-Signature: t=<timestamp>,v1=<digest>
Signed content
Timestamp, a period, and the unmodified request body.
Algorithm
HMAC-SHA256 using the signing secret.
Delivery and recovery
Return a 2xx response within 10 seconds. Failed deliveries are retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours, then marked as failed permanently. Redirects are not followed. Do not depend on delivery order; deduplicate using the event ID and retain a processed-event cursor for recovery.
Every webhook update with a non-null URL rotates the signing secret, even when the URL is unchanged. Copy the new secret from that response. Pending deliveries are cancelled on rotation. Retrieve missed events from GET /v1/events using the last processed cursor.
Signature verification · Node.js
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyWebhook(secret, header, rawBody, now = Date.now()) {
if (typeof header !== "string" || !Buffer.isBuffer(rawBody)) return false;
const match = /^t=([0-9]{1,12}),v1=([a-f0-9]{64})$/.exec(header);
if (!match || !Number.isFinite(now)) return false;
const timestamp = Number(match[1]);
if (Math.abs(now / 1000 - timestamp) > 300) return false;
const expected = createHmac("sha256", secret)
.update(match[1] + ".")
.update(rawBody)
.digest();
const received = Buffer.from(match[2], "hex");
return received.length === expected.length &&
timingSafeEqual(received, expected);
}
Pass the raw body as a Buffer. Missing, malformed, expired or mismatched signatures return false.
Account
GET/v1/me
Retrieve account details
Returns account status, server quotas, concurrent provisioning limits and credit availability for the authenticated account.
Responses
200Account details.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
partnerrequired
idrequired
integer
statusrequired
activefrozensuspended
tenant_keyrequired
string
inflightrequired
currentrequired
integer
maxrequired
integer
serversrequired
countrequired
integer
maxrequired
integernullable
limitsrequired
max_inflightrequired
integer
max_serversrequired
integernullable
credit_limitrequired
stringnullable
creditrequired
limitrequired
stringnullable
Credit limit; null = no limit
unbilledrequired
stringnullable
Current usage + closed uninvoiced usage + open invoice balances - free credit, floored at 0; null while billing data is degraded
availablerequired
stringnullable
limit - unbilled; creates are refused with 402 CREDIT_LIMIT at 0
breakdownrequired
usage_month_to_daterequired
stringnullable
closed_uninvoicedrequired
stringnullable
open_invoicesrequired
stringnullable
credit_balancerequired
stringnullable
degradedrequired
boolean
True when current billing data is unavailable. Credit availability is treated as zero until recovery.
as_ofrequired
string
snapshot_as_ofrequired
stringnullable
Native financial snapshot time; null while degraded
keyrequired
key_idrequired
string
labelrequired
stringnullable
401Authentication failed. The API key is missing, invalid or revoked, or API access is not approved.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
Returns active plans in the account's assigned price book. Prices and discounts are account-specific. An empty list means no plans are currently available to order.
Responses
200Available plans and prices.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
Creates a server asynchronously. Set dry_run to true to validate the configuration and retrieve pricing without creating a server. If neither a password nor SSH keys are supplied, the generated root password is returned once. A 202 response confirms acceptance, not completion. Poll the returned server until its status changes; reuse the same idempotency key after a timeout. Billing start depends on the account's discount basis; see Billing.
Required when dry_run is false or omitted. Use one unique value per intended server and reuse it for retries with the same request body. Retained for 24 hours. An unfinished request returns 409 CONFLICT with details.reason=request_in_progress and Retry-After. A different body returns 409 IDEMPOTENCY_MISMATCH.
Server hostname. Lowercase DNS labels separated by dots; unique among live servers in this account.
planrequired
stringmaximum 32 characters, minimum 1 characters
Plan code returned by GET /v1/plans.
regionrequired
stringmaximum 32 characters, minimum 1 characters
Region code returned by GET /v1/regions.
imagerequired
stringmaximum 32 characters, minimum 1 characters
Operating system image code returned by GET /v1/images.
ssh_keysoptional
array ofintegergreater than 0maximum 20 items
IDs of registered SSH public keys owned by this account. Maximum 20 keys.
passwordoptional
stringmaximum 20 characters, minimum 8 characters
Root password, 8–20 characters. If omitted with no SSH keys, a password is generated and returned once.
user_dataoptional
string
Cloud-init configuration or shell script. Must begin with #cloud-config or #! and be at most 65,536 UTF-8 bytes after CRLF normalization. Requires an image with cloud_init enabled.
external_idoptional
stringmaximum 64 characters, minimum 1 characters
Identifier from your system. Must be unique across this account, including deleted server records.
batchoptional
stringmaximum 64 characters, minimum 1 characters
Optional group label for filtering related servers.
dry_runoptional
boolean
When true, validate and return pricing without creating a server. Does not require Idempotency-Key.
Responses
200Configuration validated. Returned only for dry_run.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
403FROZEN, PARTNER_SUSPENDED or QUOTA: account state or server quota prevents creation. NETWORK_RESTRICTED: the request source is outside this deployment's approved IP networks.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
409CONFLICT or IDEMPOTENCY_MISMATCH: duplicate name or external_id, unfinished or expired idempotency key, or key used with a different body. For request_in_progress, wait for Retry-After and retry with the same key. A persistent conflict requires reconciling details.server_id with support.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
Retry-After
Minimum delay in seconds before retrying, when present. Some dependency failures omit this header; use exponential backoff with jitter.
Permanently deletes the server. Active or suspended servers transition to destroying; billing ends when deletion is accepted. Returns 204 if the server is already destroying, destroyed or failed. Locked servers and servers in requested, provisioning or rebuilding state return 409.
Parameters
idpath, required
string
Server identifier returned by the API.
Responses
202Deletion accepted; server status is destroying.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
Supports reboot, start, stop, reset_password and rebuild on active servers. reset_password returns the password generated by the compute platform once; its task ID can be null. Rebuild overwrites the server disk with the selected image while preserving the server ID, IP address and billing interval. Supply SSH keys or a password, or receive a generated password once. Rebuild can return a null task ID; monitor the returned server and events. Rebuild failure requires checking task and event details; a return to active does not confirm a successful reinstall.
Parameters
idpath, required
string
Server identifier returned by the API.
Request body
actionrequired
rebootstartstopreset_password
or
actionrequired
"rebuild"
imagerequired
stringmaximum 32 characters, minimum 1 characters
Operating system image code returned by GET /v1/images.
ssh_keysoptional
array ofintegergreater than 0maximum 20 items
IDs of registered SSH public keys owned by this account. Maximum 20 keys.
passwordoptional
stringmaximum 20 characters, minimum 8 characters
Root password, 8–20 characters. If omitted with no SSH keys, a password is generated and returned once.
user_dataoptional
string
Cloud-init configuration or shell script. Must begin with #cloud-config or #! and be at most 65,536 UTF-8 bytes after CRLF normalization. Requires an image with cloud_init enabled.
Responses
202Action accepted. Poll task.id when present.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
taskrequired
idrequired
integernullable
Task identifier for polling, or null when the operation returned no task.
actionrequired
string
Operation performed by this task.
statusrequired
string
Task status: pending or running is incomplete; done is success; failed or canceled is unsuccessful. Treat unknown values as unresolved.
server_idoptional
string
Associated server ID, included when retrieving a task.
passwordoptional
string
Generated root password, shown once for reset_password or a rebuild with neither password nor non-empty ssh_keys. A supplied password is not echoed.
Registers an OpenSSH public key for use in create and rebuild requests. Supports Ed25519, RSA and ECDSA public keys. Submit the complete public key, never its private key.
Creates a backup of the server disk. Requires an active or suspended server and backups.enabled=true for its plan. The current plan setting is enforced on every request. When task.id is null, poll the server backup list to track completion.
Parameters
idpath, required
string
Server identifier returned by the API.
Responses
202Backup task accepted.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
taskrequired
idrequired
integernullable
Task identifier for polling, or null when the operation returned no task.
actionrequired
string
Operation performed by this task.
statusrequired
string
Task status: pending or running is incomplete; done is success; failed or canceled is unsuccessful. Treat unknown values as unresolved.
server_idoptional
string
Associated server ID, included when retrieving a task.
401Authentication failed. The API key is missing, invalid or revoked, or API access is not approved.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
403FORBIDDEN with details.reason=backups_disabled: the plan disables backups or its configuration is missing. NETWORK_RESTRICTED: the request source is outside this deployment's approved IP networks.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
Overwrites the server disk with this backup. The backup must belong to the server. Requires an active or suspended server and backups.enabled=true for its plan, enforced on every request. This operation does not create a new server.
Parameters
idpath, required
string
Server identifier returned by the API.
bidpath, required
integerminimum 1
Backup identifier returned by the server's backup list.
Responses
202Restore task accepted.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
taskrequired
idrequired
integernullable
Task identifier for polling, or null when the operation returned no task.
actionrequired
string
Operation performed by this task.
statusrequired
string
Task status: pending or running is incomplete; done is success; failed or canceled is unsuccessful. Treat unknown values as unresolved.
server_idoptional
string
Associated server ID, included when retrieving a task.
401Authentication failed. The API key is missing, invalid or revoked, or API access is not approved.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
403FORBIDDEN with details.reason=backups_disabled: the plan disables backups or its configuration is missing. NETWORK_RESTRICTED: the request source is outside this deployment's approved IP networks.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
Returns a task associated with a server in the authenticated account. Task IDs are integers; server IDs are strings. done indicates success, failed or canceled is unsuccessful, and pending or running is incomplete. Poll at intervals of five seconds or longer. action is the platform task name and can differ from the submitted action, for example vm-restart for reboot.
Parameters
idpath, required
integerminimum 1
Task identifier returned by an asynchronous operation.
Responses
200Task details.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
taskrequired
idrequired
integernullable
Task identifier for polling, or null when the operation returned no task.
actionrequired
string
Operation performed by this task.
statusrequired
string
Task status: pending or running is incomplete; done is success; failed or canceled is unsuccessful. Treat unknown values as unresolved.
server_idoptional
string
Associated server ID, included when retrieving a task.
401Authentication failed. The API key is missing, invalid or revoked, or API access is not approved.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
Returns account events in ascending ID order. Use after to resume from the last processed event. Webhook test events are excluded. Poll at intervals of 10 seconds or longer, or use webhooks for delivery and this endpoint for recovery.
Parameters
afterquery
integerminimum 0
Return events with an ID greater than this cursor.
Sets or disables the destination URL. Every request with a non-null URL rotates the signing secret, including requests that repeat the existing URL. The new secret is returned once. Pending deliveries are cancelled; recover missed events through GET /v1/events. This operation is not safe to retry automatically.
Attempts one synchronous delivery of a signed webhook.test event. HTTP 200 indicates the test ran; inspect ok and status for the delivery result. Response bodies from the destination are not returned.
Responses
200Delivery result. status is the destination's HTTP status, or 0 for a connection failure.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
statusrequired
integer
latency_msrequired
integer
okrequired
boolean
erroroptional
string
401Authentication failed. The API key is missing, invalid or revoked, or API access is not approved.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
Displayed hourly rate at this allocation count; use returned charges for billing totals.
next_from_countrequired
integernullable
Next discount threshold, or null when there is no higher tier.
period_segmentsoptional
array of
fromrequired
stringdate-time
torequired
stringdate-time
qualifying_countrequired
integer
monthly_pricerequired
string
hourly_pricerequired
string
hoursrequired
integer
charge_numeratorrequired
string
Exact charge numerator: monthly price in cents multiplied by billed hours. Divide by 672 for cents. Sum numerators before rounding the plan total.
subtotalrequired
string
Rounded display amount for this segment; independently rounded segments may not sum to the final plan amount.
coderequired
string
hoursrequired
number
capped_hoursrequired
number
vm_monthsrequired
number
Capped hours divided by 672, to four decimals. Used for tier selection with vm_months_per_plan; allocation-based pricing uses charges recorded for each hour.
monthly_pricerequired
string
Monthly price at the selected VM-month tier, or current allocation-count tier. It does not reprice historical allocated usage.
hourly_pricerequired
string
Displayed hourly rate at the same tier. Use amount for the period's charge.
amountrequired
string
tieroptional
hoursrequired
number
vm_monthsrequired
number
from_vm_monthsrequired
number
monthly_pricerequired
string
nextrequired
from_vm_monthsrequired
number
monthly_pricerequired
string
nullable
nullable
totalrequired
string
401Authentication failed. The API key is missing, invalid or revoked, or API access is not approved.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.
Returns month-to-date charges, a month-end projection and the next invoice estimate. The projection assumes the current fleet remains allocated until month end with no server creations or deletions. Use next_invoice.issued_on and due_on for the invoice dates.
Responses
200Billing estimate.
Response headers
X-Request-Id
Request identifier. Include this value when contacting support.