NoKycVPS REST API reference offshore VPS automation and provisioning
00 · Conventions

Conventions

The same set of rules applies to every endpoint in this document. Read this once, then jump to the resource you need.

Authentication

Every request must include a bearer token in the Authorization header:

Authorization: Bearer nkv_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2

Three scopes are available, each strictly broader than the previous:

  • read — read-only access to all resources except billing.
  • write — read + create/update/destroy. Cannot generate top-up addresses.
  • billing — everything write can do, plus the billing endpoints.

Tokens are minted at Account → API tokens. The plaintext is shown once at creation — we store only its SHA-256 digest. Clock skew tolerance for any time-based check is 30 seconds.

JSON & types

  • Request bodies must be application/json. We do not accept multipart/form-data except on POST /images.
  • Keys are snake_case. Unknown keys in requests are rejected with 400; unknown keys in responses can be safely ignored by your client.
  • Timestamps are RFC 3339 in UTC, e.g. 2026-05-12T08:47:12Z.
  • Money is rendered as a JSON number in USD with two decimal places. Coin amounts are rendered as a decimal string to preserve precision.
  • Resource IDs are short, prefix-typed, opaque strings. Don\'t parse them.

Idempotency

Every POST endpoint accepts an optional Idempotency-Key header. A UUIDv4 is the standard choice. The first response for a given key is cached for 24 hours; subsequent requests with the same key replay the cached response. A different request body with the same key returns 409 conflict_state.

curl -X POST .../v1/servers \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Authorization: Bearer $NOKYC_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{...}'

Pagination

List endpoints return up to 25 items by default, 100 max. Cursor-based; no offset. A response that has more items returns has_more: true and a next_cursor. Pass it as ?cursor=... to fetch the next page.

jsonlist response shape
{
  "object":      "list",
  "data":        [ /* up to page_size items */ ],
  "has_more":    true,
  "next_cursor": "c_8a1f2c34"
}

Use page_size to override the default. filter[field]=value for equality filters where supported. sort=-created_at for descending sort.

Errors

Errors always return JSON in the same envelope:

jsonerror envelope
{
  "error": {
    "code":       "invalid_request",
    "message":    "ssh_keys must contain at least one valid key id.",
    "errors": [
      { "field": "ssh_keys", "issue": "min_items", "min": 1 }
    ],
    "request_id": "req_2f8b1c4e9d"
  }
}

Always log request_id in your client — it is the only thing we can use to find your call in our logs if you ask us to look at one. (We will only look at lines you give us a request_id for; we do not browse customer logs.)

HTTP status codes and their semantic codes:

HTTPCodeMeaning
400invalid_requestBody or query parameters did not validate. See errors[].
401unauthenticatedMissing, malformed, or expired bearer token.
403forbidden_scopeToken does not have the required scope.
404not_foundResource does not exist or is not visible to your account.
409conflict_stateResource is in a state that does not allow this op (e.g. attaching an already-attached volume).
422unprocessableBody parsed but semantic validation failed (e.g. unavailable region for a plan).
429rate_limitedToken bucket exhausted. Retry-After header in seconds.
451jurisdictional_blockEndpoint refused for legal reasons. Canary will reflect.
500internalServer-side error. Retry only idempotent ops.
503maintenanceEndpoint temporarily down during a published maintenance window.

Rate limits

60 requests/minute per token with a 10-request burst. Bucket replenishes at 1 req/s. Provisioning endpoints (POST /servers, POST /images) use a separate 200 req/minute bucket because they are inherently bursty.

X-RateLimit-Limit:     60
X-RateLimit-Remaining: 57
X-RateLimit-Reset:     1747049892
Retry-After:           23           # only on 429

Versioning

The API is versioned in the path: /v1/.... We commit to:

  • No backwards-incompatible change within a major version.
  • Additive changes (new fields, new endpoints) on the existing version, announced in the changelog.
  • A 12-month deprecation window before any endpoint or field is removed in the next major.
  • Beta endpoints are gated behind X-Nokyc-Beta: true and may break without notice.
Resources

Resources

Each resource below is documented as a triplet: the object schema, the endpoints that act on it, and one or more example requests with their actual response bodies.

01 · core

Servers

A server is one virtual machine on our hypervisor pool, or one physical node in the dedicated tier. Every other resource on this page either describes a server, attaches to one, or generates events from one.

Object

FieldTypeDescription
id ro string Unique identifier. Prefix srv_.
object ro string Always "server".
name string · 1–63 Customer-provided name. [a-z0-9-], must start with a letter.
status ro enum provisioning, installing, running, stopped, suspended, destroying.
plan string Plan id (see Plans). Immutable after deploy.
region string Region code (see Regions). Immutable.
image string Image id at install time. Updated when the server is rebuilt.
ipv4 ro object · nullable {address, gateway, rdns}. Null until running.
ipv6 ro object · nullable {address, prefix, rdns}. Always a routed /64.
ssh_keys array<string> SSH key ids injected at install time.
user_data_b64 string · write-only Base64-encoded cloud-init user-data. Up to 64 KiB.
tags array<string> Free-form tags. Useful for filtering.
labels object<string,string> Up to 32 key/value pairs. Keys must match [a-z0-9_-]{1,63}.
created_at ro string · RFC 3339 UTC timestamp.
updated_at ro string · RFC 3339 UTC timestamp. Bumped on any mutation.

Endpoints

  • GET /servers List your servers.
  • POST /servers Create a new server.
  • GET /servers/{id} Retrieve a single server.
  • PATCH /servers/{id} Update name, tags, or labels.
  • DELETE /servers/{id} Destroy a server. Irreversible.
  • POST /servers/{id}/reboot Reboot. Add ?hard=true to skip ACPI.
  • POST /servers/{id}/rebuild Reinstall the OS image. Destroys disk data.
  • POST /servers/{id}/rescue Boot into the rescue ISO.
  • POST /servers/{id}/stop Graceful stop (ACPI poweroff).
  • POST /servers/{id}/start Start a stopped server.
  • GET /servers/{id}/console One-time signed noVNC URL (5 min validity).
  • GET /servers/{id}/metrics 30-day CPU / RAM / disk / bandwidth rollup.
  • POST /servers/{id}/rdns Set reverse DNS for IPv4 and/or IPv6.
02 · resources

Images

An image is the disk template a server boots from. Official images are maintained by us; custom images are ISOs you uploaded.

Object

FieldTypeDescription
id ro string Prefix img_ (official) or custom_ (custom upload).
object ro string Always "image".
type ro enum official or custom.
family ro string debian, ubuntu, alpine, etc. custom for uploads.
version ro string Upstream version (e.g. 13, 24.04, rolling).
variant ro string · nullable Image variant: minimal, cloud, etc.
arch ro array<string> Supported architectures: amd64, arm64.
size_gb ro number On-disk size, GiB. Useful for predicting deploy time.
cloud_init ro boolean Whether the image ships cloud-init.
released_at ro string · ISO 8601 Date this version was published.
deprecated_at ro string · ISO 8601 · nullable If set, image is read-only and will be removed 90 days after this date.

Endpoints

  • GET /images List images (filter by family, arch, type).
  • GET /images/{id} Retrieve a single image.
  • POST /images Upload a custom ISO. multipart/form-data, 4 GiB max.
  • DELETE /images/{id} Delete a custom image (no-op on official images).
02 · resources

Plans

A plan describes one purchasable hardware tier. Prices are USD-reference; the actual amount charged in coin is derived at the spot rate when the daily charge runs.

Object

FieldTypeDescription
id ro string Plan code. Stable across pricing changes.
object ro string Always "plan".
category ro enum vps or dedicated.
cpu ro integer vCPU count (VPS) or physical core count (dedicated).
cpu_model ro string Marketing-free silicon string, e.g. "AMD EPYC 7763 (Milan)".
ram_mb ro integer RAM in MiB.
disk_gb ro integer NVMe disk in GiB.
transfer_tb ro number Monthly outbound transfer in TiB. Inbound is unmetered.
price_usd_month ro number Reference monthly price in USD.
price_usd_hour ro number Hourly cost (used by the daily-charge prorater).
available_in ro array<string> Region codes where this plan is currently provisionable.

Endpoints

  • GET /plans List plans.
  • GET /plans/{id} Retrieve a plan.
02 · resources

Regions

A region is one of our four PoPs. Each is operated by a separate legal entity and routed independently.

Object

FieldTypeDescription
id ro string Three-letter code: par, rkv, zrh, buh.
object ro string Always "region".
name ro string Human name (Paris, Reykjavík, Zürich, Bucharest).
country ro string ISO 3166-1 alpha-2.
pop_id ro string Internal PoP designation (e.g. nky-par-01).
available ro boolean true if at least one plan can currently be provisioned.
ipv4_pool_remaining ro integer IPv4 addresses left in the regional pool. Sub-50 means provisioning may stall.
tor_onion ro string · nullable Per-region onion endpoint, if available.

Endpoints

  • GET /regions List regions.
  • GET /regions/{id} Retrieve a region.
02 · resources

SSH keys

Public keys injected into server authorized_keys at install time. The private half never leaves your machine and is never seen by us.

Object

FieldTypeDescription
id ro string Prefix k_.
object ro string Always "ssh_key".
name string · 1–63 Display name for your benefit.
type ro enum ssh-ed25519 · ssh-rsa · ecdsa-sha2-nistp{256,384,521}.
fingerprint ro string SHA-256, base64-encoded. Format SHA256:<digest>.
public_key string OpenSSH-format public key (omitted from list responses for size).
created_at ro string · RFC 3339

Endpoints

  • GET /ssh-keys List SSH keys.
  • POST /ssh-keys Add a new SSH key.
  • GET /ssh-keys/{id} Retrieve a key.
  • DELETE /ssh-keys/{id} Remove a key. Does not affect already-deployed servers.
02 · resources

API tokens

Long-lived secrets used to authenticate against this API. The plaintext token is returned once at creation; only its SHA-256 digest is stored server-side.

Object

FieldTypeDescription
id ro string Prefix tok_.
object ro string Always "api_token".
name string For your own bookkeeping.
scope enum read, write, or billing.
token string · write-only Plaintext token. Returned once, in the POST response. Format nkv_live_<52 chars>.
last_used_at ro string · RFC 3339 · nullable Updated at most once per minute to bound write amplification.
expires_at string · RFC 3339 · nullable Optional. If set, the token stops working at this timestamp.
created_at ro string · RFC 3339

Endpoints

  • GET /account/tokens List tokens.
  • POST /account/tokens Create a token (returns plaintext once).
  • DELETE /account/tokens/{id} Revoke a token immediately.
03 · billing

Billing

Read-mostly endpoints describing your current balance, your transaction history, and the top-up flow.

The balance object

FieldTypeDescription
object ro string Always "balance".
usd ro number USD-reference balance, two decimals.
as_of ro string · RFC 3339 Snapshot time.
runway_until ro string · date · nullable Calendar date the balance will hit zero at current burn. null if no running servers.
active_servers ro integer Servers currently incurring daily charges.
daily_cost_usd ro number Sum of daily prorated cost for all running servers.
low_balance_at ro string · RFC 3339 · nullable When we will email a low-balance warning (currently 7d before runway).

Endpoints

  • GET /billing/balance Current balance + runway.
  • GET /billing/ledger Paginated transaction history (charges, top-ups, credits).
  • POST /billing/topup Generate a one-time deposit address for a given coin.
  • GET /billing/topup/{id} Poll a top-up intent (pending / confirming / credited / expired).
04 · storage

Volumes

Persistent block storage that can be attached to a server in the same region. Volumes survive server destruction.

Object

FieldTypeDescription
id ro string Prefix vol_.
object ro string Always "volume".
name string Display name.
size_gb integer · 10–4096 Size in GiB. Can be increased online (not decreased).
region string Region code. Must match attached server's region.
attached_to ro string · nullable Server id, or null if detached.
device ro string · nullable Linux block device path when attached (/dev/vdb, …).
encrypted boolean Volume-level LUKS, customer-held key passed via cloud-init.
filesystem string · nullable For your bookkeeping. We don't format volumes.
created_at ro string · RFC 3339

Endpoints

  • GET /volumes List volumes.
  • POST /volumes Create a volume.
  • GET /volumes/{id} Retrieve.
  • PATCH /volumes/{id} Resize (only size_gb increase) or rename.
  • DELETE /volumes/{id} Destroy. Must be detached first.
  • POST /volumes/{id}/attach Attach to a server (body: {"server":"srv_…"}).
  • POST /volumes/{id}/detach Detach.
04 · storage

Snapshots

Point-in-time image of a server's root disk. Snapshots are deduplicated and stored encrypted at rest. Cannot be exported — they exist to let you rebuild from a known-good state.

Object

FieldTypeDescription
id ro string Prefix snap_.
object ro string Always "snapshot".
server ro string Server id this snapshot was taken from. Frozen at creation.
name string Display name.
size_gb ro number Deduped size; the actual storage you pay for.
status ro enum creating · ready · error.
expires_at string · RFC 3339 · nullable Optional auto-delete date.
created_at ro string · RFC 3339

Endpoints

  • GET /snapshots List snapshots.
  • POST /servers/{id}/snapshots Take a snapshot of a server.
  • GET /snapshots/{id} Retrieve.
  • POST /servers/{id}/restore Restore a server from a snapshot (rebuild from snap_…).
  • DELETE /snapshots/{id} Delete a snapshot.
05 · networking

Firewall groups

Stateful, drop-by-default packet filter enforced at the hypervisor — outside the guest. A group is a named set of rules; each rule allows ingress or egress traffic matching a 5-tuple.

Object

FieldTypeDescription
id ro string Prefix fwg_.
object ro string Always "firewall_group".
name string Display name.
applied_to array<string> Server ids that inherit this group.
rules array<rule> See rule object below. Order matters: first match wins.
default_action enum drop (recommended) or accept.
created_at ro string · RFC 3339

Rule object

FieldTypeDescription
id ro string Prefix fwr_. Assigned server-side.
direction enum in or out.
proto enum tcp · udp · icmp · any.
port string · nullable Single port ("22"), comma list ("80,443"), or range ("5000-5100"). Null for non-port protocols.
source string CIDR. 0.0.0.0/0 and ::/0 are accepted.
action enum accept, drop, or reject (sends RST/ICMP-unreach).
note string · nullable Optional comment.

Endpoints

  • GET /firewall/groups List firewall groups.
  • POST /firewall/groups Create a group.
  • GET /firewall/groups/{id} Retrieve.
  • PATCH /firewall/groups/{id} Update name, default_action, applied_to.
  • DELETE /firewall/groups/{id} Delete the group (must not be applied).
  • POST /firewall/groups/{id}/rules Append a rule.
  • PUT /firewall/groups/{id}/rules Replace the rule list (atomic).
  • DELETE /firewall/groups/{id}/rules/{rule_id} Remove a single rule.
06 · automation

Webhook subscriptions

Subscribe a URL to events from your account. We POST a JSON event to your endpoint each time something interesting happens, signed with an HMAC-SHA256 you can verify.

Object

FieldTypeDescription
id ro string Prefix whk_.
object ro string Always "webhook".
url string · HTTPS only Endpoint we POST to. HTTPS with a valid certificate required.
events array<string> Subscribed events. ["*"] subscribes to all.
active boolean If false, deliveries are paused.
secret_hint ro string Last 4 chars of the signing secret (whsec_…) for your reference. Full secret returned once at creation.
created_at ro string · RFC 3339

Endpoints

  • GET /webhooks List subscriptions.
  • POST /webhooks Create. Response includes secret (plaintext, once).
  • GET /webhooks/{id} Retrieve.
  • PATCH /webhooks/{id} Update url, events, active.
  • DELETE /webhooks/{id} Unsubscribe.
  • POST /webhooks/{id}/test Send a synthetic ping event.
  • GET /webhooks/{id}/deliveries Last 7 days of delivery attempts.
07 · observability

Audit log

Every authenticated, state-changing request made against your account, with the actor that made it. 90-day retention.

Object

FieldTypeDescription
id ro string Prefix audit_.
object ro string Always "audit_event".
action ro string Dotted operation name (e.g. server.create).
resource ro string · nullable Affected resource id.
actor_token ro string · nullable Token id used, if API.
actor_session ro string · nullable Session id used, if dashboard.
request_id ro string Correlation id (shared with the X-Request-Id header on the original response).
ip_country ro string ISO-3166 country code at probe time. No IP stored.
result ro enum ok · error · denied.
created_at ro string · RFC 3339

Endpoints

  • GET /audit/events List audit events. Filterable by action, resource, from, to.
  • GET /audit/events/{id} Retrieve one event.
Example · create a server

End-to-end deploy in one shell session

The minimum viable flow from "I have an account" to "I have a running server":

Request

curlPOST /v1/servers
curl https://api.nokycvps.com/v1/servers \
  -H "Authorization: Bearer $NOKYC_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "name":     "edge-paris",
    "plan":     "vps-s2",
    "region":   "par",
    "image":    "debian-13-minimal",
    "ssh_keys": ["k_5f3a8c91"],
    "tags":     ["production","edge"],
    "labels":   { "owner":"ops" },
    "user_data_b64": null
  }'

Response — 201 Created

jsonserver object
{
  "id":         "srv_8a1f2c34",
  "object":     "server",
  "name":       "edge-paris",
  "status":     "provisioning",
  "plan":       "vps-s2",
  "region":     "par",
  "image":      "debian-13-minimal",
  "ipv4":       null,
  "ipv6":       null,
  "ssh_keys":   ["k_5f3a8c91"],
  "tags":       ["production","edge"],
  "labels":     { "owner":"ops" },
  "created_at": "2026-05-12T08:47:12Z",
  "updated_at": "2026-05-12T08:47:12Z"
}

Two webhook events later (typically 60–120 s):

jsonserver.running webhook
{
  "id":         "evt_3c8a1f4b",
  "object":     "event",
  "type":       "server.running",
  "created_at": "2026-05-12T08:48:34Z",
  "data": {
    "server": {
      "id":     "srv_8a1f2c34",
      "status": "running",
      "ipv4":   { "address":"198.51.100.42", "gateway":"198.51.100.1", "rdns":null },
      "ipv6":   { "address":"2001:db8::1",   "prefix":"2001:db8::/64", "rdns":null }
    }
  }
}

You can ssh [email protected] now.

08 · Webhook events

Event catalogue

Every event is one of the types below. The data envelope contains the full object as it existed at event time — you should not re-fetch unless you need a guaranteed-fresh view.

EventWhen it fires
server.created A new server has begun provisioning.
server.running Server has finished installing and is reachable.
server.stopped Server gracefully shut down.
server.rebooted Server completed a reboot cycle.
server.rebuilt Server finished a rebuild from an image.
server.suspended Balance went negative; server stopped.
server.destroyed Server's disk has been wiped and IPs released.
snapshot.ready Snapshot moved from creating to ready.
volume.attached Volume successfully attached.
volume.detached Volume detached.
topup.pending Deposit detected on chain; waiting for confirmations.
topup.confirmed Deposit confirmed; balance credited.
topup.expired Rate lock expired before confirmation.
billing.charged Daily charge applied. Includes amount and resulting balance.
billing.low_balance Balance projects to zero within 7 days at current burn.
token.created A new API token was created.
token.revoked An API token was revoked.
firewall.applied A firewall group was attached to a server.
09 · Webhook signing

Verifying webhook authenticity

Every delivery includes an X-Nokyc-Signature header. You compare it against an HMAC-SHA256 of the request body, keyed by the secret returned to you at subscription time.

Header format

X-Nokyc-Signature:   t=1747049892,v1=4f8c1a...e9d
X-Nokyc-Delivery-Id: del_7c3a1f9b
Content-Type:        application/json
  • t — Unix epoch the signature was generated.
  • v1 — lowercase hex HMAC-SHA256 of "{t}.{raw_body}".
  • Reject any delivery where t drifts more than 5 minutes from your clock.

Verification — Python

pythonverify_signature.py
import hmac, hashlib, time

def verify(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    t  = int(parts["t"])
    v1 = parts["v1"]
    if abs(time.time() - t) > tolerance:
        return False
    payload = f"{t}.".encode() + raw_body
    expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(v1, expected)

Retry policy

Each delivery is attempted up to 6 times at the following back-off intervals:

attempt 1:  immediate
attempt 2:  + 1   minute
attempt 3:  + 5   minutes
attempt 4:  + 30  minutes
attempt 5:  + 5   hours
attempt 6:  + 24  hours
              => give up

A delivery succeeds when your endpoint returns HTTP 2xx within 10 seconds. 410 Gone short-circuits all future attempts and pauses the subscription. Failed deliveries are visible via GET /webhooks/{id}/deliveries.

10 · Changelog

Changelog

Additive changes within v1. The next major version (v2) is not currently scheduled.

  1. v1.4 2026-04-22
    • Added /servers/{id}/metrics endpoint (30-day rollup).
    • Added runway_until and low_balance_at to the balance object.
    • Webhooks now include X-Nokyc-Delivery-Id for replay-safety.
  2. v1.3 2026-01-10
    • Added Volumes resource (block storage with attach/detach).
    • Firewall groups gained default_action and note on rules.
    • Server labels capped at 32 pairs (was 16).
  3. v1.2 2025-09-15
    • Added Snapshots resource and /servers/{id}/restore.
    • Added ipv4_pool_remaining on regions.
  4. v1.1 2025-06-04
    • Switched list endpoints to cursor pagination. offset/limit deprecated; will be removed in v2.
    • Added Idempotency-Key support on every POST.
    • Added Audit log resource.
  5. v1.0 2024-09-12
    • Initial stable release.
    • Servers, Images, Plans, Regions, SSH Keys, API Tokens, Billing, Webhooks.