Skip to main content

Developer reference

REST API reference

20 endpoints under /api/v1 — clients, orders, invoices, services, products, nodes, platform status and an OpenAI-compatible AI Router. Every sample below is generated from the endpoint specification, so the method, parameters and body always match what the API accepts.

New to the API? Start with the OpenAI-compatible quickstart. Tokens are issued by our staff — send us the scopes you need with a support request.

Base URL

All endpoints are served from https://hostingswift.com/api/v1. Paths in this reference are relative to that base. JSON in, JSON out, UTF-8.

Authentication

  • API token — Authorization: Bearer hs_… — a token created in the client panel, sent on every request.
  • AI key — Authorization: Bearer hs-sk-… — an AI Router key with the `chat` scope, OpenAI-compatible auth.
  • None (public) — No credentials required. Read-only, cached, and never includes customer data.

Tokens carry scopes such as services:read or invoices:write. A request that needs a scope the token does not hold gets 403 insufficient_scope. Accounts with an admin role bypass scope checks. Tokens are stored as hashes — we can never show one again, so keep it in a secret manager.

curl https://hostingswift.com/api/v1/status \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN"

Errors

Failures use one JSON shape, and validation failures add an issues array naming each field.

application/json
{
  "error": {
    "message": "Token missing required scope(s): invoices:write",
    "code": "insufficient_scope"
  }
}
  • 400 Malformed request — usually an invalid JSON body (`invalid_json`).
  • 401 Missing, invalid, revoked or expired token.
  • 403 Token lacks a required scope (`insufficient_scope`), account inactive, or an admin-only change.
  • 404 The record does not exist (`not_found`).
  • 409 Conflict — duplicate email or slug, or the service is already terminated.
  • 413 Body over the size limit (AI Router: 2 MB).
  • 422 Validation failed (`validation_error`) — `error.issues` lists each field.
  • 429 Rate limited or AI budget exhausted.
  • 503 Authentication backend or rate limiter unavailable.

Catalogue

What you can sell or order. The catalogue endpoint is public; products are token-protected.

GET

/api/v1/ai/catalog

link

Public product catalogue with prices, locations and endpoints — safe for AI agents to crawl.

Authentication
None (public)
Required scopes
None (any valid token, or public)

Request

curl -X GET "https://hostingswift.com/api/v1/ai/catalog"

Response · 200

application/json
{
  "provider": "HostingSwift",
  "url": "https://hostingswift.com",
  "currency": "USD",
  "locations": ["…"],
  "services": [
    { "slug": "vps", "name": "VPS hosting", "products": [ { "slug": "…", "prices": [] } ] }
  ]
}
GET

/api/v1/products

link

List products, optionally filtered by group or service type.

Authentication
API token
Required scopes
products:read
Parameters for GET /products
ParameterTypeRequiredDescription
groupIdstringNoOnly products in this product group.
serviceTypestringNoOnly products of this service type.

Request

curl -X GET "https://hostingswift.com/api/v1/products" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN"

Response · 200

application/json
{ "data": [ { "id": "prod_…", "slug": "vps-2gb", "name": "VPS 2 GB", "groupId": "grp_…", "serviceType": "VPS" } ] }
POST

/api/v1/products

link

Create a product in an existing product group.

Authentication
API token
Required scopes
products:write
Parameters for POST /products
ParameterTypeRequiredDescription
slugstringYesLowercase kebab-case, unique across products.
namestringYesDisplay name.
groupIdstringYesExisting product group id.
serviceTypestringYesService type key, e.g. VPS.
taglinestringNoOne-line summary.
descriptionstringNoLong description (markdown).
isFreebooleanNoFree-tier product.
visiblebooleanNoListed on the public site.
featuredbooleanNoHighlighted on the storefront.
provisioningKeystringNoProvisioning recipe key.
cpuCoresintegerNovCPU count.
ramMbintegerNoMemory in MB.
diskGbintegerNoDisk in GB.
bandwidthGbintegerNoMonthly transfer in GB.

Errors: 404 — Product group not found. 409 — A product with that slug already exists. 422 — Validation failed — see `error.issues`.

Request

curl -X POST "https://hostingswift.com/api/v1/products" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "slug": "vps-2gb",
  "name": "VPS 2 GB",
  "groupId": "grp_vps",
  "serviceType": "VPS",
  "ramMb": 2048,
  "diskGb": 40
}'

Response · 201

application/json
{ "data": { "id": "prod_…", "slug": "vps-2gb", "name": "VPS 2 GB" } }

Orders and invoices

Place an order for a client and issue the invoice. Pricing is always resolved server-side.

GET

/api/v1/orders

link

List orders.

Authentication
API token
Required scopes
orders:read
Parameters for GET /orders
ParameterTypeRequiredDescription
statusstringNoFilter by order status.
userIdstringNoOnly orders for this client.
limitintegerNoPage size, 1–200. Default 50.
offsetintegerNoRows to skip. Default 0.

Request

curl -X GET "https://hostingswift.com/api/v1/orders" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN"

Response · 200

application/json
{ "data": [ { "id": "ord_…", "status": "PENDING", "userId": "usr_…", "total": "12.00" } ], "meta": { "total": 128, "limit": 50, "offset": 0 } }
POST

/api/v1/orders

link

Create an order (and, by default, its invoice) for a client.

Authentication
API token
Required scopes
orders:write
Parameters for POST /orders
ParameterTypeRequiredDescription
userIdstringYesClient the order belongs to.
itemsarrayYesAt least one item: `{ productId, quantity?, cycle? }`. Cycle is FREE, MONTHLY, QUARTERLY, SEMIANNUAL, ANNUAL or BIENNIAL.
currencystringNoISO-4217 code, 3 letters.
promoCodestringNoPromotion code to apply.
ipAddressstringNoIP recorded against the order (fraud checks).
createInvoicebooleanNoIssue the invoice immediately.

Errors: 404 — User not found. 422 — Validation failed or the product cannot be priced.

Request

curl -X POST "https://hostingswift.com/api/v1/orders" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "userId": "usr_abc123",
  "items": [
    {
      "productId": "prod_vps2gb",
      "quantity": 1,
      "cycle": "MONTHLY"
    }
  ],
  "createInvoice": true
}'

Response · 201

application/json
{ "data": { "order": { "id": "ord_…" }, "invoice": { "id": "inv_…", "number": "HS-1042" } } }
GET

/api/v1/invoices

link

List invoices with their line items and client.

Authentication
API token
Required scopes
invoices:read
Parameters for GET /invoices
ParameterTypeRequiredDescription
statusstringNoFilter by invoice status.
userIdstringNoOnly invoices for this client.
limitintegerNoPage size, 1–200. Default 50.
offsetintegerNoRows to skip. Default 0.

Request

curl -X GET "https://hostingswift.com/api/v1/invoices" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN"

Response · 200

application/json
{ "data": [ { "id": "inv_…", "number": "HS-1042", "status": "UNPAID", "total": "12.00", "items": [], "user": { "email": "…" } } ], "meta": { "total": 128, "limit": 50, "offset": 0 } }
POST

/api/v1/invoices

link

Create a standalone invoice (manual charges) for a client.

Authentication
API token
Required scopes
invoices:write
Parameters for POST /invoices
ParameterTypeRequiredDescription
userIdstringYesClient to invoice.
itemsarrayYesAt least one line: `{ unitPrice, description?, productName?, cycle?, quantity? }`. `unitPrice` is required and non-negative.
dueInDaysintegerNoPositive number of days until due.

Errors: 404 — User not found. 422 — Validation failed — see `error.issues`.

Request

curl -X POST "https://hostingswift.com/api/v1/invoices" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "userId": "usr_abc123",
  "items": [
    {
      "description": "Migration assistance",
      "unitPrice": 75,
      "quantity": 1
    }
  ],
  "dueInDays": 14
}'

Response · 201

application/json
{ "data": { "id": "inv_…", "number": "HS-1043", "status": "UNPAID" } }
PATCH

/api/v1/invoices

link

Mark an invoice paid (manual payment reconciliation). Records an `invoice.paid` audit event.

Authentication
API token
Required scopes
invoices:write
Parameters for PATCH /invoices
ParameterTypeRequiredDescription
idstringYesInvoice id — a QUERY parameter on this endpoint, not a path segment.
gatewaystringNoPayment gateway that took the money. Defaults to `manual`.
transactionIdstringNoGateway transaction reference, or null.
amountnumberNoAmount received. Defaults to the invoice total.

Errors: 400 — Missing query parameter `id`. 404 — Invoice not found.

Request

curl -X PATCH "https://hostingswift.com/api/v1/invoices?id=inv_abc123" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "gateway": "manual",
  "transactionId": "BANK-9931",
  "amount": "12.00"
}'

Response · 200

application/json
{ "data": { "id": "inv_…", "status": "PAID" } }

Clients

Create and maintain client accounts. Only an admin may change a role.

GET

/api/v1/clients

link

List clients, with free-text search across email, name and company.

Authentication
API token
Required scopes
clients:read
Parameters for GET /clients
ParameterTypeRequiredDescription
qstringNoCase-insensitive search across email, first/last name and company.
limitintegerNoPage size, 1–200. Default 50.
offsetintegerNoRows to skip. Default 0.

Request

curl -X GET "https://hostingswift.com/api/v1/clients" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN"

Response · 200

application/json
{ "data": [ { "id": "usr_…", "email": "…", "firstName": "…", "role": "CLIENT", "status": "active" } ], "meta": { "total": 128, "limit": 50, "offset": 0 } }
POST

/api/v1/clients

link

Create a client account.

Authentication
API token
Required scopes
clients:write
Parameters for POST /clients
ParameterTypeRequiredDescription
emailstringYesMust be a valid email and not already taken.
firstNamestringNoGiven name.
lastNamestringNoFamily name.
companystringNoCompany name.
phonestringNoPhone number.
countrystringNoTwo-letter code. Defaults to US.
rolestringNoCLIENT, STAFF or ADMIN. Defaults to CLIENT.
statusstringNoactive, suspended or closed. Defaults to active.

Errors: 409 — A user with that email already exists. 422 — Validation failed — see `error.issues`.

Request

curl -X POST "https://hostingswift.com/api/v1/clients" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "[email protected]",
  "firstName": "Ada",
  "lastName": "Lovelace",
  "country": "GB"
}'

Response · 201

application/json
{ "data": { "id": "usr_…", "email": "…", "role": "CLIENT", "status": "active" } }
GET

/api/v1/clients/:id

link

Fetch one client with counts of their related records.

Authentication
API token
Required scopes
clients:read
Parameters for GET /clients/:id
ParameterTypeRequiredDescription
idstringYesClient id (path parameter).

Errors: 404 — Client not found.

Request

curl -X GET "https://hostingswift.com/api/v1/clients/usr_abc123" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN"

Response · 200

application/json
{ "data": { "id": "usr_…", "email": "…", "counts": { "services": 2, "invoices": 7 } } }
PATCH

/api/v1/clients/:id

link

Update a client. Sending `role` or `staffRole` requires an admin.

Authentication
API token
Required scopes
clients:write
Parameters for PATCH /clients/:id
ParameterTypeRequiredDescription
idstringYesClient id (path parameter).
firstNamestringNoGiven name, or null to clear.
lastNamestringNoFamily name, or null to clear.
companystringNoCompany, or null to clear.
phonestringNoPhone, or null to clear.
countrystringNoTwo-letter code.
rolestringNoCLIENT, STAFF or ADMIN — admin only.
statusstringNoactive, suspended or closed.
staffRolestringNoStaff role key, or null — admin only.

Errors: 403 — Only an admin may change roles. 404 — Client not found. 422 — Validation failed.

Request

curl -X PATCH "https://hostingswift.com/api/v1/clients/usr_abc123" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "company": "Analytical Engines Ltd",
  "country": "GB"
}'

Response · 200

application/json
{ "data": { "id": "usr_…", "email": "…", "status": "suspended" } }

Services

Read the services you run and trigger lifecycle actions. Actions are queued as jobs.

GET

/api/v1/services

link

List services with their client and node.

Authentication
API token
Required scopes
services:read
Parameters for GET /services
ParameterTypeRequiredDescription
statusstringNoFilter by service status, e.g. ACTIVE.
userIdstringNoOnly services for this client.
nodeIdstringNoOnly services on this node.
limitintegerNoPage size, 1–200. Default 50.
offsetintegerNoRows to skip. Default 0.

Request

curl -X GET "https://hostingswift.com/api/v1/services" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN"

Response · 200

application/json
{ "data": [ { "id": "svc_…", "status": "ACTIVE", "node": { "name": "…" }, "user": { "email": "…" } } ], "meta": { "total": 128, "limit": 50, "offset": 0 } }
POST

/api/v1/services/:id/actions

link

Queue a lifecycle action on a service: suspend, unsuspend, terminate or reboot.

Authentication
API token
Required scopes
services:write
Parameters for POST /services/:id/actions
ParameterTypeRequiredDescription
idstringYesService id (path parameter).
actionstringYessuspend, unsuspend, terminate or reboot.

Errors: 404 — Service not found. 409 — Service is already terminated. 422 — Validation failed.

Request

curl -X POST "https://hostingswift.com/api/v1/services/svc_abc123/actions" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "action": "reboot"
}'

Response · 202

application/json
{ "data": { "serviceId": "svc_…", "action": "reboot", "jobId": "job_…" } }

Infrastructure

Nodes and platform health. Node API tokens are never returned.

GET

/api/v1/nodes

link

List nodes with capacity and counts of services and IPs.

Authentication
API token
Required scopes
nodes:read

Request

curl -X GET "https://hostingswift.com/api/v1/nodes" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN"

Response · 200

application/json
{ "data": [ { "id": "nod_…", "name": "…", "hypervisor": "…", "status": "ONLINE", "serviceCount": 12, "ipCount": 40 } ] }
GET

/api/v1/status

link

Platform health: database and Redis reachability plus aggregate counts.

Authentication
API token
Required scopes
None (any valid token, or public)

Request

curl -X GET "https://hostingswift.com/api/v1/status" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN"

Response · 200

application/json
{
  "data": {
    "status": "ok",
    "time": "2026-01-01T00:00:00.000Z",
    "checks": { "db": { "ok": true }, "redis": { "ok": true } },
    "counts": { "services": { "ACTIVE": 120 }, "nodes": { "ONLINE": 9 }, "jobs": { "DONE": 40 } }
  }
}

AI Router

OpenAI-compatible alias on the same base path, so the OpenAI SDKs work by changing `baseURL`.

POST

/api/v1/chat/completions

link

Create a chat completion. Request and response are OpenAI-compatible; `stream: true` returns SSE.

Authentication
AI key
Required scopes
chat
Parameters for POST /chat/completions
ParameterTypeRequiredDescription
modelstringYesA model id from GET /models.
messagesarrayYes1–200 messages with a role of system, user, assistant or tool.
streambooleanNoStream the reply as server-sent events.
max_tokensintegerNo1–8192.
temperaturenumberNoSampling temperature.

Errors: 401 — Invalid or revoked AI key. 413 — Payload over 2 MB. 422 — Invalid request (message includes which field). 429 — Rate limited or budget exhausted.

Request

curl -X POST "https://hostingswift.com/api/v1/chat/completions" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "model": "deepseek-chat",
  "messages": [
    {
      "role": "user",
      "content": "Explain DNS TTLs in two sentences."
    }
  ]
}'

Response · 200

application/json
{ "id": "chatcmpl-…", "object": "chat.completion", "model": "…", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "…" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 12, "completion_tokens": 40, "total_tokens": 52 } }
GET

/api/v1/models

link

List chat models enabled for this key, with context length and prices.

Authentication
AI key
Required scopes
chat

Request

curl -X GET "https://hostingswift.com/api/v1/models" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN"

Response · 200

application/json
{ "object": "list", "data": [ { "id": "deepseek-chat", "object": "model", "owned_by": "hostingswift", "context_length": 64000, "free": false } ] }

Cloudflare automation

One endpoint that drives DNS, SSL, WAF, DDoS and cache through our cfk tooling — one shared rate budget (10% of Cloudflare's) and one audit trail. Mutating actions require `confirm: true`.

GET

/api/v1/cloudflare

link

Discovery: what this key may do — its scopes and the read/write action list.

Authentication
AI key
Required scopes
dns

Errors: 401 — Missing, invalid or revoked key. 403 — Key lacks the `dns` scope, or is not staff and not delegated.

Request

curl -X GET "https://hostingswift.com/api/v1/cloudflare" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN"

Response · 200

application/json
{
  "ok": true,
  "service": "HostingSwift Cloudflare automation API",
  "version": 1,
  "keyId": "key_…",
  "scopes": ["chat", "dns"],
  "actions": {
    "read": ["zone.list", "zone.settings", "dns.list", "ssl.get", "waf.list", "waf.rules", "ddos.status", "ddos.analytics", "raw"],
    "write": ["dns.upsert", "dns.delete", "ssl.set-mode", "waf.ip-block", "waf.ip-allow", "cache.purge"]
  }
}
POST

/api/v1/cloudflare

link

Run one action. Read: zone.list, zone.settings, dns.list, ssl.get, waf.list, waf.rules, ddos.status, ddos.analytics, raw. Write (need `confirm: true` and the `dns` scope, not `dns:read`): dns.upsert, dns.delete, ssl.set-mode, waf.ip-block, waf.ip-allow, cache.purge.

Authentication
AI key
Required scopes
dns
Parameters for POST /cloudflare
ParameterTypeRequiredDescription
actionstringYesOne of the actions listed above, max 40 chars.
zonestringNoZone id or name — required by every zone-scoped action.
accountstringNoCloudflare account key, when the key spans several.
namestringNoRecord name (dns.upsert).
typestringNoRecord type (dns.upsert, dns.list filter).
contentstringNoRecord value (dns.upsert).
ttlintegerNo1–86400 (dns.upsert).
proxiedbooleanNoOrange-cloud the record (dns.upsert).
recordIdstringNoRecord id (dns.delete).
modestringNooff, flexible, full or strict (ssl.set-mode).
ipstringNoAddress for waf.ip-block / waf.ip-allow.
notesstringNoNotes for the firewall rule.
pathstringNoGET-only zone-relative API path (raw), must start with /.
confirmbooleanNoMust be true for every mutating action (otherwise 428).

Errors: 403 — Key is read-only (`dns:read`) or not authorised for Cloudflare automation. 422 — Unknown action, invalid request, or a required field is missing. 428 — Mutating action without `confirm: true`. 429 — Rate limited (60 requests/minute per key). 503 — cfk not installed on this host.

Request

curl -X POST "https://hostingswift.com/api/v1/cloudflare" \
  -H "Authorization: Bearer $HOSTINGSWIFT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "action": "dns.upsert",
  "zone": "example.com",
  "name": "www.example.com",
  "type": "A",
  "content": "203.0.113.10",
  "ttl": 300,
  "proxied": true,
  "confirm": true
}'

Response · 200

application/json
{ "ok": true, "result": { "…": "action-specific payload from Cloudflare" } }

Need something not listed here?

The API is the same one our own panel uses. If you need an endpoint that is missing, tell us what it should do and we will scope it.

Talk to us