Gigahost API documentation for clients. Integrate servers and services directly into your own system or panel.
Current API version: 0
Base URL: https://api.gigahost.no/api/v0
To communicate with our API you need to authenticate. To do this, use the /authenticate endpoint.
Add the received token to your header: Authorization: Bearer {token}
Its expected that all PUT/POST requests are json encoded.
Send your login email and password as a JSON body. The returned token is valid for 24 hours and the expiry is pushed forward 24 hours on every request made with it. Send it as Authorization: Bearer {token}.
Required parameters
username (string - body) - login email address, or sub-client username (GH-xxxxx)
password (string - body)
Optional parameters
code (numeric - body) - 6-digit code from your authenticator app, required when 2FA is enabled
newpassword1 (string - body) - new password, only when the response asks for a password change
newpassword2 (string - body) - repeat of newpassword1
sms_code (numeric - body) - 6-digit code sent by SMS, only when the response asks for it
Example request body
{
"username":"[email protected]",
"password":"yourpassword",
"code":"123456"
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"maintenance":false,
"time":1712000000
},
"data":{
"token":"0123456789abcdef0123456789abcdef",
"token_expire":1712086400,
"customer_id":"1111",
"contact_id":"5",
"customer_name":"Example AS",
"contact_username":"[email protected]",
"contact_access_level":"admin",
"customer_address":"Example Road 1",
"customer_zipcode":"0150",
"customer_city":"Oslo",
"customer_province":"Oslo",
"contact_language":"en",
"ga_secret":"XXXXXXXXXXXXXXXX",
"ga_enabled":"0",
"payment_automated":0,
"vat":1
}
}
All API responses use this envelope: a meta object (status, status_message, maintenance, time and, on errors, message) and a data object or array, which is empty when there is nothing to return.
contact_access_level is admin, user or server for account users, and subclient for sub-client logins (which also return client_id). ga_secret is the secret for setting up an authenticator app (see /account/2fa) and is empty once 2FA is enabled, ga_enabled tells whether 2FA is on, and vat is 1 when Norwegian VAT applies to the account.
Two-factor, SMS and password-change steps
// Some new accounts must verify their phone number once. The first request
// sends a 6-digit code by SMS: repeat the request with "sms_code".
// Repeating it without sms_code sends a new code once retry_after has passed.
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"need_sms":true,
"phone_hint":"67",
"retry_after":60
}
}
// Wrong or expired SMS code
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid verification code.",
"need_sms":true,
"sms_failed":true,
"phone_hint":"67"
}
}
// 2FA is enabled and no code was sent: repeat the request with "code"
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"need2fa":true
}
}
// Wrong 2FA code
{
"meta":{
"status":403,
"status_message":"403 Forbidden",
"message":"Unable to verify 2fa code.",
"twofactorfailed":true
}
}
// The password is a one-time password and must be changed:
// repeat the request with newpassword1 and newpassword2
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"otp_change_needed":true
}
}
If the password change is rejected, the response also carries otp_change_failed, password_too_short (under 6 characters), password_same (same as the old one) or password_in_breach (weak or found in a known data breach).
Other errors
// Wrong username or password
{
"meta":{
"status":403,
"status_message":"403 Forbidden",
"message":"Username or password is invalid."
}
}
// The email address has not been verified yet
{
"meta":{
"status":403,
"status_message":"403 Forbidden",
"message":"Account email has not been validated."
}
}
Users who have turned off password login (passkey-only, see /account/passwordlogin) cannot use this endpoint; passkey sign-in is only available in the control panel.
HTTP Basic Auth is accepted only by the DynDNS endpoint (GET /dns/dyndns), so that standard DynDNS clients can update records. All other endpoints require a Bearer token (session token or API key) and return 401 for Basic Auth. No 2FA code is asked for on this endpoint.
Send your credentials in the Authorization header:
Authorization: Basic base64(username:password)
Important: The username is your email address. If it contains special characters (e.g. + or @), you must URL-encode it when passing it in a URL.
Example: [email protected] becomes user%2Btag%40example.com
Example with curl:
# Using --user (curl handles encoding):
curl --user "[email protected]:yourpassword" "https://api.gigahost.no/api/v0/dns/dyndns?hostname=home.example.com"
# Using inline URL credentials (URL-encode the username):
curl "https://user%40example.com:[email protected]/api/v0/dns/dyndns?hostname=home.example.com"
For unattended integrations you can authenticate with a personal API key instead of a username/password Bearer token. Each key has a permissions object that restricts what it can read or change, and (for DNS, servers, and webhosting) can be limited to a specific list of resource IDs. API keys are used directly; do not send them to /authenticate.
Send the key in the Authorization header just like a session token:
Authorization: Bearer flux_live_<hex>
Example with curl:
curl -H "Authorization: Bearer flux_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" https://api.gigahost.no/api/v0/servers
Security model: the full secret is shown only once, at creation time. After that the secret cannot be recovered, so rotate or delete the key if it is lost. List and read responses return only the key_prefix (the first part of the secret, safe to display). API keys cannot manage other API keys.
An optional expires_at (Unix timestamp) auto-revokes the key once reached. See /account/apikeys for management endpoints.
The token sent in the Authorization header stops working immediately. Other sessions are not affected. API keys are not affected either; revoke them with DELETE /account/apikeys/{id}.
Parameters
{none}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"maintenance":false,
"time":1712000000,
"message":"200 OK"
},
"data":[]
}
Announce your own IP space from your servers: register your ASN, set up BGP sessions with our routers, and follow traffic and received prefixes per ASN.
The flow is: submit your ASN with POST /bgp/asn, prove ownership by adding the authorization token you receive by email to your ASN object in your RIR database, wait for the ASN status to become active, then create sessions for one or more of your server IPs with POST /bgp/{asn_id}/session. Read operations need a token or API key with read access to servers; creating and deleting needs read-write access to servers. Not available to sub-client logins.
Parameters
{none}
ASN status is one of pending (awaiting ownership verification), active or rejected (see rejected_reason). irr_v4 / irr_v6 are the AS-SETs or AS numbers used to build your prefix lists, and irr_updated is when the prefix lists were last rebuilt (Unix timestamp).
Each prefix list entry is one prefix you are allowed to announce: prefix_exact is 1 when only the exact prefix is accepted, otherwise prefix_less_equal / prefix_greater_equal give the accepted prefix-length range. prefix_source is where the entry came from (irr). prefix_added is a Unix timestamp.
Sessions with status deleted are not returned. Session status is pending (waiting to be configured), active or deletion (removal in progress). defaultroute is 1 when the session sends you a default route only, 0 for the full routing table. neighbor_ipv4 / neighbor_ipv6 are the router addresses to peer with (use the one matching ip_type), router_asn is our ASN and multihop is the eBGP multihop TTL (0 when not used). ip_address is your server address used for the session. session_state (for example Established), prefix_received and prefix_accepted are refreshed periodically; session_state_updated is a Unix timestamp.
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"asn":[
{
"id":"1",
"asn":"64500",
"asn_name":"EXAMPLE-NET",
"asn_country":"NO",
"irr_v4":"AS-EXAMPLE",
"irr_v6":"AS-EXAMPLE",
"irr_updated":"1700000000",
"status":"active",
"rejected_reason":""
}
],
"prefix_lists":[
{
"id":"1",
"asn_id":"1",
"prefix":"198.51.100.0/24",
"prefix_exact":"1",
"prefix_less_equal":"",
"prefix_greater_equal":"",
"prefix_type":"ipv4",
"prefix_source":"irr",
"prefix_added":"1700000000",
"your_asn":"64500",
"asn_country":"NO"
}
],
"sessions":[
{
"id":"1",
"asn_id":"1",
"cust_id":"1111",
"router_id":"1",
"srv_id":"3523",
"ip_id":"7795",
"ip_type":"ipv4",
"custom_ip":"",
"defaultroute":"0",
"status":"active",
"session_state":"Established",
"prefix_received":"2",
"prefix_accepted":"2",
"session_state_updated":"1700000000",
"neighbor_ipv4":"192.0.2.1",
"neighbor_ipv6":"2001:db8::1",
"multihop":"2",
"router_asn":"39029",
"your_asn":"64500",
"asn_country":"NO",
"ip_address":"192.0.2.24"
}
]
}
}
Required parameters
asn_id (numeric - inurl - the ASN's id from GET /bgp, not the AS number)
Optional parameters
range (string - query) - day (default), week, month, year or custom
from (string - query) - start date YYYY-MM-DD, required when range is custom
to (string - query) - end date YYYY-MM-DD (inclusive), required when range is custom
The resolution follows the length of the period: 5-minute points (step 300) for up to 2 days, hourly points (3600) for up to 60 days and daily points (86400) beyond that. Timestamps are local time (Europe/Oslo). The series ends at the latest available data point; missing points are returned as 0. Returns 401 if the ASN does not belong to you.
Example request
GET /bgp/1/traffic?range=custom&from=2026-09-01&to=2026-09-30
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"timeseries":[
{
"timestamp":"2026-10-04 12:00:00",
"egress_mbps":152.3121,
"ingress_mbps":48.9013
},
{
"timestamp":"2026-10-04 12:05:00",
"egress_mbps":149.8875,
"ingress_mbps":51.2201
}
],
"step":300,
"from":"2026-10-04 12:00:00",
"to":"2026-10-05 12:00:00",
"range":"day"
}
}
Error responses
// Unknown range
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid range."
}
}
// range=custom without from/to
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Custom range requires from and to parameters."
}
}
Required parameters
asn_id (numeric - inurl - the ASN's id from GET /bgp)
Current rates are from the latest 5-minute sample. Month-to-date volumes (in GB, 10^9 bytes) and the 95th percentile (from 5-minute samples) cover the calendar month given in billing_month. Returns 401 if the ASN does not belong to you.
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"current_egress_mbps":152.31,
"current_ingress_mbps":48.9,
"mtd_egress_gb":2210.45,
"mtd_ingress_gb":640.12,
"mtd_total_gb":2850.57,
"p95_egress_mbps":310.2,
"p95_ingress_mbps":95.77,
"billing_month":"2026-10-01"
}
}
Required parameters
asn_id (numeric - inurl - the ASN's id from GET /bgp)
The list is refreshed periodically, see updated_at. srv_id and session_id identify the server and BGP session the prefix was received on (0 when it is not tied to one of your servers). Returns 401 if the ASN does not belong to you.
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"prefixes":[
{
"prefix":"198.51.100.0",
"prefix_length":"24",
"prefix_type":"ipv4",
"srv_id":"3523",
"session_id":"1",
"router_id":"1",
"updated_at":"2026-10-05 11:55:00"
}
]
}
}
Maximum 3 ASNs per customer (rejected ASNs also count; contact support to remove one). After submission an email with an authorization token is sent to you. Add the token to your ASN object in your RIR database (for example in a remarks field). The ASN is checked automatically and becomes active once the token is found. If the token is not found within 48 hours, the ASN is set to rejected.
Note: unlike most endpoints, this endpoint reads a form-encoded body (application/x-www-form-urlencoded or multipart/form-data), not JSON.
Required parameters
asn (numeric or string - body, form field) - ASN number, e.g. "64500" or "AS64500"
Example request
curl -X POST -H "Authorization: Bearer {token}" -d "asn=AS64500" https://api.gigahost.no/api/v0/bgp/asn
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"ASN and LOA has been submitted for review."
}
}
Error responses
// Invalid ASN
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"ASN is not valid"
}
}
// Maximum ASNs reached
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Only three ASNs can be configured at a time. Contact support to remove an ASN first."
}
}
// ASN already exists
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"The ASN already exists in the database."
}
}
The ASN must have status active. The IPs must belong to one of your servers. Sessions are created against up to two routers in the server's datacenter, one session per router for each address you give. New sessions have status pending until they have been configured; follow them with GET /bgp.
Required parameters
asn_id (numeric - inurl - the ASN's id from GET /bgp, not the AS number)
redundant (numeric - body - 0 or 1. Must be numeric; sessions are currently always created on up to two routers regardless of the value)
defaultroute (numeric - body - 1 to receive a default route only, 0 to receive the full routing table)
Optional parameters
ip_id_v4 (numeric - body - ip_id of the server's IPv4 address, from the ips list in GET /servers/{id})
ip_id_v6 (numeric - body - ip_id of the server's IPv6 address, from the ips list in GET /servers/{id})
At least one of ip_id_v4 or ip_id_v6 should be provided.
Example request body
{
"redundant":1,
"defaultroute":0,
"ip_id_v4":"7795",
"ip_id_v6":"7796"
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"BGP sessions has been created."
}
}
Error responses
// Non-numeric values, ASN not found / not active, or IP not on one of your servers
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid data received."
}
}
// Session already exists for the address
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"IPv4 session exists already."
}
}
// No routers available in the server's datacenter
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Unable to find available BGP routers."
}
}
The session must have status active and belong to you, otherwise 401 is returned. The session gets status deletion and is removed from the routers shortly after. Each session (one per router and address) is deleted separately.
Required parameters
session_id (numeric - inurl - the session's id from GET /bgp)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"BGP sessions have been marked for deletion."
}
}
Manage DNS zones and records on Gigahost nameservers, register and transfer domains (.no and a range of international TLDs), manage registrant contacts, DNSSEC, HTTP redirects and dynamic DNS.
API keys. These endpoints use the dns permission category. A read-only key ("r") can only call GET endpoints. A key limited to specific zone IDs can only call endpoints that carry one of those IDs in the path (/dns/zones/{zone_id}/...), plus list endpoints, which are filtered automatically. Such a key cannot create zones, register or transfer domains, or call other write endpoints that do not address a zone ID. Domain transfer codes (domain_auth_info) are never returned to API keys.
Public endpoints. GET /dns/domains/check/{domain} and GET /dns/pricing do not require authentication.
Parameters
org_number (numeric - 9 digits - inurl)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Company lookup successful"
},
"data":{
"company_name":"Example AS",
"address":"Exampleveien 1",
"zip_code":"0123",
"city":"Oslo"
}
}
Works for .no and every other TLD listed by GET /dns/pricing. Unsupported TLDs return 400 "This TLD is not available for registration.". Internationalized domain names are accepted and returned in punycode form. No authentication is required.
Required parameters
domain (string - inurl, e.g. example.no or example.com)
Optional parameters
transfer (any non-empty value - query parameter. Set when checking a domain you want to transfer in, so premium pricing is detected for the transfer. International TLDs only.)
The pricing object is included when a price exists for the TLD. Premium domains have premium set to true and a price in NOK that applies to both registration and renewal. min_year is the minimum registration period in years for the TLD.
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Domain availability checked"
},
"data":{
"domain":"example.no",
"available":true,
"reason":"",
"pricing":{
"registration_price":85,
"renewal_price":85,
"currency":"NOK",
"premium":false,
"min_year":1
}
}
}
No authentication is required. min_year is the minimum registration period in years.
Parameters
{none}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"pricing":[
{
"tld":"com",
"registration_price":"149.00",
"renewal_price":"149.00",
"currency":"NOK",
"min_year":"1"
},
{
"tld":"no",
"registration_price":"85.00",
"renewal_price":"85.00",
"currency":"NOK",
"min_year":"1"
}
]
}
}
Each zone includes the live record count, the time of the last change, the current apex nameservers and the ID of a webhosting account using the zone (0 if none). external_dns is 1 when the domain is delegated to nameservers other than Gigahost's. domain_auth_info holds the transfer (auth) code for registered domains. It is empty for suspended domains and when authenticated with an API key.
Rows can contain additional fields that are not documented here. Rely only on the documented fields.
Parameters
{none}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":[
{
"zone_id":"123",
"cust_id":"1111",
"zone_name":"example.no",
"zone_name_display":"example.no",
"zone_type":"NATIVE",
"zone_active":"1",
"zone_protected":"1",
"zone_is_registered":"1",
"zone_suspended":"0",
"domain_status":"active",
"domain_registered_date":"2024-12-31 12:00:00",
"domain_expiry_date":"2025-12-31 23:59:59",
"domain_auto_renew":"1",
"domain_dnssec":"0",
"domain_auth_info":"",
"external_dns":"0",
"record_count":5,
"zone_updated":1700000000,
"nameservers":[
"ns1.gigahost.no",
"ns2.gigahost.no",
"ns3.gigahost.no"
],
"hosting_id":0
}
]
}
Supports both JSON and multipart/form-data (for zone file import). Without a zone file, the zone is created with default A records for @ and www pointing to the Gigahost parking page. Your account profile (address, postal code, city, country) must be complete. The number of zones that are not registered domains is limited per account.
Set transfer_domain and auth_code to also start a transfer of the domain to Gigahost. Unless use_existing_ns is true, the domain is moved to Gigahost nameservers and, for .no domains, any existing DS records are removed. For TLDs other than .no the transfer also needs the registrant object (see POST /dns/domains/register for contact fields).
.co.uk domains have no auth code: leave auth_code empty and ask the current registrar to change the domain's IPS tag to ASCIO. The transfer completes once the tag has been changed, and the response then also includes ips_tag.
Required parameters (JSON)
zone_name (string - domain name)
Optional parameters (JSON)
zone_type (string - "NATIVE" or "MASTER", default: "NATIVE")
create_default_records (boolean - default: false)
transfer_domain (boolean - initiate a domain transfer, default: false)
auth_code (string - required if transfer_domain is true, except for .co.uk)
use_existing_ns (boolean - keep the domain's existing nameservers, default: false)
registrant (object - required for transfers of TLDs other than .no; first_name, last_name and email are mandatory)
admin_contact (object - optional, transfers of TLDs other than .no; defaults to the registrant)
tech_contact (object - optional, transfers of TLDs other than .no)
billing_contact (object - optional, transfers of TLDs other than .no)
For zone file import (multipart/form-data):
zone_name (string)
zone_file (file - BIND zone file, max 2MB)
The optional fields above can be sent as form fields. Contact objects are sent as JSON-encoded strings.
The new zone ID is returned in meta.
Example return data
{
"meta":{
"status":201,
"status_message":"201 Created",
"message":"Zone created successfully.",
"zone_id":123
},
"data":[]
}
Error responses
// Zone already exists
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Zone already exists."
}
}
// A transfer is already running
{
"meta":{
"status":409,
"status_message":"409 Conflict",
"message":"A transfer for this domain is already in progress."
}
}
The zone is created with zone_type "PTR". Add PTR records to it with POST /dns/zones/{zone_id}/records. The new zone ID is returned in meta.
Required parameters
prefix (string - IP prefix, e.g. "185.181.63" or "2a03:94e0::")
ip_version (string - "ipv4" or "ipv6")
zone_name (string - PTR zone name, e.g. "63.181.185.in-addr.arpa" or "0.e.4.9.3.0.a.2.ip6.arpa")
Example request body (IPv4)
{
"prefix":"185.181.63",
"ip_version":"ipv4",
"zone_name":"63.181.185.in-addr.arpa"
}
Example request body (IPv6)
{
"prefix":"2a03:94e0::",
"ip_version":"ipv6",
"zone_name":"0.e.4.9.3.0.a.2.ip6.arpa"
}
Example return data
{
"meta":{
"status":201,
"status_message":"201 Created",
"message":"PTR zone created successfully.",
"zone_id":456
},
"data":[]
}
Error responses
// Invalid zone name format
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid IPv4 PTR zone name format."
}
}
// Zone already exists
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"PTR zone already exists."
}
}
All existing records except NS and SOA are deleted before the records from the file are imported. Send the request as multipart/form-data.
Required parameters
zone_id (numeric - inurl)
zone_file (file - BIND zone file, max 2MB)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"12 records imported successfully."
},
"data":{
"imported":12,
"failed":0,
"skipped":0,
"deleted":4
}
}
Error responses
// No usable records
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"No valid records found in zone file."
}
}
Protected zones (registered domains) cannot be deleted
Parameters
zone_id (numeric - inurl)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Zone deleted successfully."
}
}
Error responses
// Registered domain
{
"meta":{
"status":403,
"status_message":"403 Forbidden",
"message":"This zone is protected and cannot be deleted. Please cancel the domain registration first."
}
}
Every record in a record set is returned as its own entry, including the zone's SOA and NS records. record_name is relative to the zone ("@" for the zone apex). Hostname values (CNAME, NS, ALIAS, MX) are returned without the trailing dot, and TXT values without the surrounding quotes. For MX records the priority is returned separately in record_priority; for all other types it is null.
record_id is derived from the record's name, type and value, so it changes when the value changes.
Parameters
zone_id (numeric - inurl)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":[
{
"record_id":"0cc175b9c0f1b6a831c399e269772661",
"record_name":"@",
"record_type":"A",
"record_value":"185.125.168.166",
"record_ttl":3600,
"record_priority":null
},
{
"record_id":"92eb5ffee6ae2fec3ad71c777531578f",
"record_name":"www",
"record_type":"A",
"record_value":"185.125.168.166",
"record_ttl":3600,
"record_priority":null
},
{
"record_id":"4a8a08f09d37b73795649038408b5f33",
"record_name":"@",
"record_type":"MX",
"record_value":"mail.example.no",
"record_ttl":3600,
"record_priority":"10"
}
]
}
For A, AAAA, MX, TXT, NS, SRV, CAA and TLSA the record is added to any existing records with the same name and type. The TTL applies to the whole record set. For CNAME, ALIAS, DNAME, PTR and NAPTR the new record replaces the existing record with that name and type. A CNAME cannot be added to the zone apex or next to other records with the same name. An exact duplicate is rejected with "This record already exists.".
If the domain is not delegated to Gigahost nameservers, the record is still saved and the message is "Records created successfully but will not have effect until nameservers are changed.".
Required parameters
zone_id (numeric - inurl)
record_value (string - record content, see formats below)
Optional parameters
record_name (string - relative name, or the full name ending in the zone name, default: "@". Wildcards (*) and underscores (e.g. _acme-challenge) are allowed.)
record_type (string - A, AAAA, CNAME, ALIAS, DNAME, NS, MX, TXT, CAA, SRV, NAPTR, PTR or TLSA, default: "A")
record_ttl (numeric - 0 to 2147483647, default: 3600)
record_priority (numeric - 0 to 65535, required for MX records)
Value formats
A / AAAA: IPv4 / IPv6 address
CNAME, ALIAS, DNAME, NS, PTR: hostname (not an IP address)
MX: mail server hostname, with the priority in record_priority. A null MX ("." with priority 0) marks the domain as not accepting email and must be the only MX record.
TXT: text without quotes. Values longer than 255 characters must be split into quoted strings, e.g. "part1" "part2"
SRV: "priority weight port target", e.g. "10 5 5060 sip.example.no"
CAA: flags tag "value", e.g. 0 issue "letsencrypt.org"
TLSA: "usage selector matching-type certificate-data", e.g. "3 1 1 <hex>"
NAPTR: order preference "flags" "service" "regexp" replacement
Example request body
{
"record_name":"@",
"record_type":"MX",
"record_value":"mail.example.no",
"record_ttl":3600,
"record_priority":10
}
Example return data
{
"meta":{
"status":201,
"status_message":"201 Created",
"message":"Record created successfully."
}
}
Error responses
// Validation error
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid IPv4 address for A record."
}
}
// CNAME conflict
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"A CNAME record already exists for this name. Remove it before adding other records."
}
}
The record to change is found by record_id (from GET /dns/zones/{zone_id}/records). Its old value is removed and the new value is written. Always send the record's current record_name (relative name, as listed) and record_type, even when they do not change. The defaults are "@" and "A", and the name and type cannot be changed with this endpoint. To rename a record or change its type, create a new record and delete the old one. If no record matches record_id, the value is added as a new record. The TTL applies to the whole record set. The same validation and value formats as for creating records apply.
Required parameters
zone_id (numeric - inurl)
record_id (string - inurl)
record_value (string - new record content)
Optional parameters
record_name (string - default: "@", must match the existing record)
record_type (string - default: "A", must match the existing record)
record_ttl (numeric - default: 3600)
record_priority (numeric - required for MX records)
Example request body
{
"record_name":"www",
"record_type":"A",
"record_value":"185.125.168.167",
"record_ttl":3600
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Record updated successfully."
}
}
The record is identified by the name, type and value query parameters. The record_id path segment is required, but it is not used to select the record.
Without value (or with an empty value), the whole record set is deleted: every record with that name and type. With value, only the record with that exact value is deleted and the rest of the set is kept. Always send value when the name and type hold more than one record, for example several MX or TXT records.
Required parameters
zone_id (numeric - inurl)
record_id (string - inurl)
name (string - query parameter, relative name as listed, "@" for the zone apex)
type (string - query parameter, e.g. A, MX, TXT)
Optional parameters
value (string - query parameter, URL-encoded. The value of the single record to delete.)
The value must match the stored record. For most types the listed record_value can be used as is:
A / AAAA, TLSA: the value as listed
CNAME, ALIAS, DNAME, NS, PTR, SRV, NAPTR: the value as listed (the trailing dot on hostnames is optional)
TXT: the value as listed, without surrounding quotes
CAA: the value as listed, including the quotes, e.g. 0 issue "letsencrypt.org"
MX: priority, a space and the host with a trailing dot, e.g. "10 mail.example.no." (record_priority + " " + record_value + "."). For a null MX use "0 .".
Example: delete all A records for www
DELETE /dns/zones/123/records/92eb5ffee6ae2fec3ad71c777531578f?name=www&type=A
Example: delete one TXT record
DELETE /dns/zones/123/records/abc123?name=_acme-challenge&type=TXT&value=gfj9Xq...Rg85nM
Example: delete one MX record
DELETE /dns/zones/123/records/abc123?name=@&type=MX&value=10%20mail.example.no.
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Record deleted successfully."
}
}
Error responses
// Missing name or type
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Record name and type required."
}
}
// No record matched name, type and value
{
"meta":{
"status":404,
"status_message":"404 Not Found",
"message":"Record not found."
}
}
A DNS zone is created for the domain, and the registration is invoiced (charged automatically when a payment method is on file). With Gigahost nameservers the zone gets default A records for @ and www. Check availability and price first with GET /dns/domains/check/{domain}. The request body depends on the TLD.
Required parameters (all TLDs)
domain_name (string - domain to register)
Optional parameters (all TLDs)
use_gigahost_ns (boolean - default: true)
nameservers (array - required if use_gigahost_ns is false, minimum 2. For .no the nameservers must answer authoritatively for the domain before registration.)
.no domains (registered with Norid)
Required parameters
registrant_type (string - "organization" or "person")
email (string - valid email address)
applicant_name (string - name of applicant, max 255 characters)
zip_code (string - postal code)
city (string - city name)
For organization registrants:
org_number (string - 9 digit organization number)
company_name (string - company name, max 255 characters)
For person registrants:
pid (string - format: N.PRI.12345678)
first_name (string)
last_name (string)
Example return data (.no)
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Domain registered successfully! You will receive a confirmation email shortly."
},
"data":{
"zone_id":123,
"domain_name":"example.no",
"expires_at":"2025-11-17",
"status":"active"
}
}
International TLDs
Required parameters
registrant (object - the domain holder)
Optional parameters
admin_contact (object - defaults to the registrant)
tech_contact (object - defaults to the registrant; for .fi and .fr, to Gigahost's technical contact)
billing_contact (object - defaults to the registrant)
whois_privacy (boolean - hide the holder's details in WHOIS where the TLD allows it, default: false. Not allowed for .fi and .co.uk.)
Contact object fields
first_name (string - required)
last_name (string - required)
address1 (string - required)
city (string - required)
postal_code (string - required)
country_code (string - required, 2-letter ISO code)
email (string - required)
phone (string - required, format +CC.NUMBER, e.g. +47.12345678)
org_name (string - optional, set when the holder is an organization)
registrant_number (string - optional, organization or personal identification number, see TLD rules below)
TLD rules for registrant_number
.es: required, 5-20 characters (company number, or passport / driving licence / national ID)
.it: required (VAT/organization number for companies, personal identification number for individuals)
.dk: required for companies (CVR or company registration number), must be empty for individuals
.se, .nu: required (organization number, or personal identity or passport number)
.fi: required (Finnish business ID or personal identity code; for holders outside Finland the company registration number, or date of birth YYYY-MM-DD for individuals). The technical contact for .fi must be an organization.
.be: the VAT number, required for organizations in the EU/EEA. Not sent for individuals.
.fr: optional organization number (SIREN, VAT number or the local company number); the registry uses it to verify the holder. Not sent for individuals.
.co.uk: the company number for UK limited companies
Other TLD rules
.fr: the registrant and the administrative contact must be resident in the EU/EEA or Switzerland
.nl: domain names with special characters (IDN) are not available. The registrant receives an email to approve the registration, which must be approved within 7 days or the registration is cancelled.
Some TLDs have a minimum registration period (min_year in the pricing). The domain is registered and invoiced for that period. Premium domains are invoiced at the premium price from the availability check.
Example request body (international)
{
"domain_name":"example.com",
"use_gigahost_ns":true,
"whois_privacy":true,
"registrant":{
"first_name":"Ola",
"last_name":"Nordmann",
"org_name":"Example AS",
"registrant_number":"999999999",
"address1":"Exampleveien 1",
"city":"Oslo",
"postal_code":"0123",
"country_code":"NO",
"email":"[email protected]",
"phone":"+47.12345678"
}
}
Example return data (international)
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Domain registered successfully."
},
"data":{
"zone_id":124,
"domain_name":"example.com",
"domain":"example.com",
"expires_at":"2026-10-05",
"status":"active"
}
}
Error responses
// Unsupported TLD
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"This TLD is not available for registration."
}
}
// Missing contact field (international)
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Registrant field 'phone' is required."
}
}
Use this when the zone is already hosted on Gigahost nameservers but the domain is still registered elsewhere. To create the zone and transfer in one step, use POST /dns/zones with transfer_domain. Some .no transfers are accepted as pending at the registry and complete later. The zone ID is returned in meta.
Required parameters
zone_name (string - domain name of the existing zone)
auth_code (string - transfer code from the current registrar. Not used for .co.uk, see below.)
TLD rules for auth_code
.co.uk: no auth code. Ask the current registrar to change the domain's IPS tag to ASCIO; the transfer completes once the tag has been changed. The response includes ips_tag.
.be: the code is requested at dns.be and sent by DNS Belgium to the holder's email address
.fr: at least 12 characters, with an upper case letter, a lower case letter and a digit
Additional parameters for TLDs other than .no
registrant (object - required, first_name, last_name and email are mandatory. Same fields and TLD rules as for POST /dns/domains/register.)
admin_contact (object - optional, defaults to the registrant)
tech_contact (object - optional)
billing_contact (object - optional)
use_existing_ns (boolean - keep the domain's current nameservers, default: false)
Example request body
{
"zone_name":"example.no",
"auth_code":"Abc123!xyz"
}
Example return data
{
"meta":{
"status":201,
"status_message":"201 Created",
"message":"Domain transfer initiated successfully.",
"zone_id":"123"
},
"data":[]
}
Error responses
// Zone missing or already registered
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Zone does not already exist or is already registered."
}
}
// Wrong code (.no)
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Failed to transfer domain example.no. Please check AUTH-code and try again."
}
}
Example return data (.co.uk)
{
"meta":{
"status":201,
"status_message":"201 Created",
"message":"Domain transfer initiated successfully. To complete it, ask your current registrar to change the IPS tag of example.co.uk to ASCIO.",
"zone_id":"123",
"ips_tag":"ASCIO"
},
"data":[]
}
Only for .no domains. The token is sent to the email address registered on the domain holder, and can then be used as auth_code when transferring. The domain does not need to exist on your account. The number of requests per domain per day is limited.
Required parameters
zone_name (string - domain name)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"A one-time token has been sent to the email address registered on the domain."
}
}
Error responses
// Daily limit reached
{
"meta":{
"status":429,
"status_message":"429 Too Many Requests",
"message":"Too many one-time token requests. Please try again tomorrow."
}
}
Mass transfers move many .no domains to Gigahost in one go. The list contains every open item plus items finished within the last 7 days.
status is one of: awaiting_code (waiting for a transfer code), queued, processing, done, registry_pending (accepted, waiting for the registry), failed, expired (no code within 48 hours) or aborted. expires_at is set while an item is waiting for a code. switch_ns is 1 when the domain is moved to Gigahost nameservers.
Parameters
{none}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"items":[
{
"item_id":42,
"batch_id":7,
"zone_id":123,
"zone_name":"example.no",
"display_name":"example.no",
"status":"awaiting_code",
"message":"",
"source":"manual",
"switch_ns":1,
"token_requested":1700000000,
"created":1700000000,
"updated":1700000000,
"expires_at":1700172800
}
]
}
}
Each item carries either a transfer code (auth_code) or request_token: true, which asks Norid to email a one-time code to the domain holder. Items with a code are queued and transferred one by one. Items waiting for a one-time code get status awaiting_code; enter the codes with PUT /dns/domains/masstransfer within 48 hours. A DNS zone is created for each domain that does not already exist on your account. Domains used by another account, already registered with Gigahost or already being transferred are returned in rejected with a reason.
Required parameters
items (array - list of domain objects, max 200)
Optional parameters
switch_ns (boolean - default for all items: move the domains to Gigahost nameservers, default: false)
Item fields
zone_name (string - required, .no domain)
auth_code (string - transfer code, max 255 characters. Required unless request_token is true.)
request_token (boolean - optional, ask Norid to email a one-time code instead)
switch_ns (boolean - optional, overrides the top-level switch_ns for this item)
Example request body
{
"switch_ns":true,
"items":[
{ "zone_name":"example.no", "auth_code":"Abc123!xyz" },
{ "zone_name":"example2.no", "request_token":true },
{ "zone_name":"example3.no", "auth_code":"Def456!xyz", "switch_ns":false }
]
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"2 domains queued for transfer, 1 waiting for a one-time code."
},
"data":{
"batch_id":7,
"accepted":["example.no","example3.no"],
"awaiting":["example2.no"],
"rejected":[]
}
}
Items that are no longer waiting for a code are skipped.
Required parameters
codes (array - objects with item_id (numeric) and auth_code (string, max 255 characters))
Example request body
{
"codes":[
{ "item_id":42, "auth_code":"Abc123!xyz" }
]
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"1 domains queued for transfer."
},
"data":{
"queued":["example2.no"]
}
}
Parameters
item_id (numeric - inurl)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"A one-time code has been sent to the email address registered on the domain."
}
}
Error responses
// Daily limit reached
{
"meta":{
"status":429,
"status_message":"429 Too Many Requests",
"message":"Too many one-time code requests for this domain today. Please try again tomorrow."
}
}
If the mass transfer created the DNS zone, the zone is removed again. Items already being processed cannot be aborted.
Parameters
item_id (numeric - inurl)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"The transfer was aborted."
}
}
The first step of moving domains from Domeneshop. Log in with an API token and secret (recommended) or with username and password. Accounts with two-factor authentication must use an API token. The credentials are used once and not stored. The result is kept for one hour; pass import_id to POST /dns/domains/masstransfer/import to start the transfer. Only .no domains are supported.
Required parameters (one of)
api_token (string) and api_secret (string)
username (string) and password (string)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"import_id":15,
"domains":[
{
"zone_name":"example.no",
"display_name":"example.no",
"supported":true,
"available":true,
"reason":"",
"on_domeneshop_ns":true,
"record_count":8,
"skipped_records":0,
"redirect_count":1,
"frommed_count":0,
"expiry_date":"2026-03-01"
}
]
}
}
Zones are created with the records and forwards read from Domeneshop (forwards become redirects). Norid emails a one-time code to each domain holder; enter the codes with PUT /dns/domains/masstransfer within 48 hours. Domains that used Domeneshop's nameservers are moved to Gigahost nameservers.
Required parameters
import_id (numeric - from POST /dns/domains/masstransfer/domeneshop, valid for one hour)
zone_names (array - domains to transfer, max 200)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"1 domains are waiting for their one-time code."
},
"data":{
"batch_id":8,
"accepted":["example.no"],
"rejected":[],
"redirects_created":1
}
}
Available for all registered domains. When disabling, an open unpaid renewal invoice is credited. When enabling again, the renewal is invoiced if needed. The message explains what happened and when the domain expires. Cannot be changed while the domain is pending at the registry (409).
Required parameters
zone_id (numeric - inurl)
auto_renew (numeric - 0 or 1)
Example request body
{
"auto_renew":0
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Auto-renewal disabled. The domain will expire on 31.12.2025."
}
}
Only available for protected zones (registered domains). The new nameservers must answer authoritatively for the domain (checked for up to 90 seconds), otherwise the change is reverted. The NS records in the Gigahost zone are updated to match. Listing ns1.gigahost.no marks the domain as hosted on Gigahost nameservers, any other set marks it as externally hosted (external_dns). For .no domains, any DS records at the registry are removed and DNSSEC is turned off when the nameservers change.
Required parameters
zone_id (numeric - inurl)
nameservers (array - minimum 2 nameservers)
Example request body
{
"nameservers":[
"ns1.example.com",
"ns2.example.com"
]
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Nameservers updated successfully."
}
}
Only available for registered .no domains. domains lists your domains that use the same contact.
Parameters
zone_id (numeric - inurl)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"contact_id":"ABC123O-NORID",
"name":"John Doe",
"organization":"Example AS",
"email":"[email protected]",
"street":["Exampleveien 1"],
"address":"Exampleveien 1",
"city":"Oslo",
"postal_code":"0123",
"country_code":"NO",
"phone":"+47.12345678",
"identity":"999999999",
"identity_type":"organizationNumber",
"type":"organization",
"domain_count":1,
"domains":[
{ "zone_id":123, "zone_name":"example.no" }
]
}
}
.no domains: requires acceptance of the Norid Applicant Declaration. The change renews the domain for 1 year, and the renewal is invoiced.
Required parameters (.no)
zone_id (numeric - inurl)
registrant_type (string - "organization" or "person")
email (string - valid email address)
applicant_name (string - name of applicant, max 255 characters)
zip_code (string - postal code)
city (string - city name)
agree_to_terms (boolean - must be true)
For organization registrants:
org_number (string - 9 digit organization number)
company_name (string - company name, max 255 characters)
For person registrants:
pid (string - format: N.PRI.XXXXXXXX)
Example return data (.no)
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Registrant changed successfully."
}
}
International TLDs: the change is submitted to the registry and completes asynchronously. You receive an email when it is done. Not available for .fi, .fr and .be domains (contact support).
Required parameters (international)
zone_id (numeric - inurl)
registrant (object - new holder, first_name, last_name and email are mandatory. Same fields and TLD rules as for POST /dns/domains/register.)
Optional parameters (international)
admin_contact (object - defaults to the new registrant)
tech_contact (object)
billing_contact (object)
Example return data (international)
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Registrant change submitted successfully."
}
}
For .no domains the registrant contact's email is updated. For international TLDs the administrative contact's email is updated. Not available for .be domains (contact support). Supports optional WHOIS email protection via whoisbeskyttelse.no forwarding. When protection is enabled, a random alias is generated and forwarding is set up to the real email address.
Required parameters
zone_id (numeric - inurl)
email (string - valid email address)
Optional parameters
enable_protection (boolean - enable WHOIS email protection, default: false)
Example request body (without protection)
{
"email":"[email protected]",
"enable_protection":false
}
Example request body (with protection)
{
"email":"[email protected]",
"enable_protection":true
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Email updated successfully"
},
"data":{
"protected":true,
"email":"[email protected]"
}
}
Error responses
// Not a registered domain
{
"meta":{
"status":403,
"status_message":"403 Forbidden",
"message":"Email can only be updated for registered domains."
}
}
.uk domains have no auth code. To move one to another registrar, enter that registrar's Nominet IPS tag. The domain is released to the new tag once the registry has processed the request, usually within one working day, and is then removed from your account. Only available for active or expired .co.uk domains registered with Gigahost. Not available to API keys, sub-clients, read-only access or suspended domains.
Required parameters
zone_id (numeric - inurl)
tag (string - IPS tag of the gaining registrar, letters, digits and hyphens. Sent in upper case.)
Example request body
{
"tag":"NEWREGISTRAR"
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"The IPS tag change to NEWREGISTRAR has been requested. The domain moves to the new registrar once the registry has processed it, usually within one working day."
},
"data":[]
}
Error responses
// Not a .co.uk domain registered with Gigahost
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"IPS tags only apply to .uk domains registered with us."
}
}
// A release is already pending
{
"meta":{
"status":409,
"status_message":"409 Conflict",
"message":"A transfer to another registrar is already in progress for this domain."
}
}
Each contact lists the domains that use it. A contact is no longer listed once no domain uses it.
Parameters
{none}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"contacts":[
{
"contact_id":"ABC123O-NORID",
"type":"organization",
"identity":"999999999",
"identity_type":"organizationNumber",
"name":"John Doe",
"organization":"Example AS",
"street":["Exampleveien 1"],
"address":"Exampleveien 1",
"postal_code":"0123",
"city":"Oslo",
"country_code":"NO",
"email":"[email protected]",
"phone":"+47.12345678",
"domain_count":2,
"domains":[
{ "zone_id":123, "zone_name":"example.no" },
{ "zone_id":124, "zone_name":"example2.no" }
]
}
]
}
}
Used to consolidate contacts. This is not a change of owner: the new contact must already be in use on one of your domains and must have the same identity (organization number or person identifier) as the current one. Nothing is invoiced. With apply_to_all, every other .no domain on your account owned by the same identity is moved as well. results reports the outcome per domain.
Required parameters
zone_id (numeric - inurl)
contact_id (string - contact to use, from GET /dns/contacts)
Optional parameters
apply_to_all (boolean - also move your other domains with the same owner, default: false)
Example request body
{
"contact_id":"ABC123O-NORID",
"apply_to_all":true
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Contact changed successfully."
},
"data":{
"results":[
{ "zone_id":124, "zone_name":"example2.no", "success":true }
]
}
}
Error responses
// Different owner
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"The selected contact belongs to a different owner. Changing owner is done through a change of registrant."
}
}
The contact must be in use on one of your domains, and the change applies to every domain using it. Only the fields you send are changed. The owner identity and the organization name cannot be changed here (use a change of registrant); sending identity, identity_type, organization or org_name returns 400. The name can only be changed on organization contacts. To refresh the organization name from Brønnøysundregistrene after the company has been renamed, set sync_org_name. With create_new, a new contact with the same owner is created for the domain in zone_id only, and other domains keep the old contact. The response contains the updated contact.
Required parameters
contact_id (string - inurl)
Optional parameters
street (array - up to 3 address lines)
postal_code (string - 4 digits for Norway)
city (string)
country_code (string - 2-letter ISO code)
phone (string - format +47.12345678)
name (string - contact person, organization contacts only, max 255 characters)
sync_org_name (boolean - refresh the organization name from Brønnøysundregistrene)
create_new (boolean - create a new contact for one domain instead of editing this one, requires zone_id)
zone_id (numeric - the domain the contact is edited from, required with create_new)
Example request body
{
"street":["Nyveien 2"],
"postal_code":"0150",
"city":"Oslo",
"phone":"+47.12345678"
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Contact details updated."
},
"data":{
"contact_id":"ABC123O-NORID",
"type":"organization",
"identity":"999999999",
"identity_type":"organizationNumber",
"name":"John Doe",
"organization":"Example AS",
"street":["Nyveien 2"],
"address":"Nyveien 2",
"postal_code":"0150",
"city":"Oslo",
"country_code":"NO",
"email":"[email protected]",
"phone":"+47.12345678"
}
}
For domains using Gigahost nameservers, the zone is signed and the DS records are submitted to the registry automatically. If the registry rejects them, DNSSEC is rolled back. For externally hosted domains, only the DNSSEC flag is set; submit the DS records from your DNS provider with POST /dns/zones/{zone_id}/ds-records/external. Disabling removes the DS records at the registry.
Required parameters
zone_id (numeric - inurl)
enable (numeric - 0 to disable, 1 to enable)
Example request body
{
"enable":1
}
Example return data (Gigahost nameservers)
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"DNSSEC enabled successfully and DS records submitted to registry"
}
}
Example return data (external nameservers)
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"DNSSEC flag enabled. Please configure DNSSEC on your nameservers."
}
}
Example return data (disable)
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"DNSSEC disabled successfully"
}
}
Error responses
// Not a registered domain
{
"meta":{
"status":403,
"status_message":"403 Forbidden",
"message":"DNSSEC can only be enabled for registered domains."
}
}
For domains using Gigahost nameservers, returns the DS records of the signed zone as text. For externally hosted domains, returns configuration instructions as text.
Parameters
zone_id (numeric - inurl)
Example return data (Gigahost nameservers)
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"ds_records":"12345 13 2 1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890AB"
}
}
Error responses
// DNSSEC not enabled
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"DNSSEC is not enabled for this domain."
}
}
Only available for domains using external nameservers. requires_dnskey is true when the registry for the domain needs the DNSKEY public key with each record (see POST below). Records submitted with a public key also include publicKey, keyType and protocol.
Parameters
zone_id (numeric - inurl)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"ds_records":[
{
"keyTag":12345,
"alg":13,
"digestType":2,
"digest":"1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF"
}
],
"requires_dnskey":false
}
}
Error responses
// Not externally hosted
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"This endpoint is only for externally hosted domains."
}
}
Only for registered domains using external nameservers. The submitted set replaces all existing DS records for the domain. The digest length must match the digest type (40, 64 or 96 hex characters). For international TLDs only digest types 1 and 2 are accepted. Registries for .be, .ch, .cz, .de, .ee, .eu, .li and .nl require the DNSKEY public key with each record. .be accepts key signing keys only (keyType 257).
Required parameters
zone_id (numeric - inurl)
ds_records (array - array of DS record objects, at least one)
DS record object fields:
keyTag (numeric - 0-65535)
alg (numeric - algorithm: 5, 7, 8, 10, 13, 14, 15, or 16)
digestType (numeric - 1 for SHA-1, 2 for SHA-256, 4 for SHA-384)
digest (string - hexadecimal digest)
publicKey (string - optional, Base64 DNSKEY public key, required by some registries)
keyType (numeric - optional, 257 (KSK) or 256 (ZSK), default: 257, used with publicKey)
Example request body
{
"ds_records":[
{
"keyTag":12345,
"alg":13,
"digestType":2,
"digest":"1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF"
}
]
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"DS records submitted successfully."
}
}
Error responses
// Invalid key tag
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid Key Tag: must be between 0-65535"
}
}
// Invalid algorithm
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid algorithm: 99"
}
}
// Wrong digest length
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid digest length for type 2: expected 64 characters"
}
}
// Not externally hosted
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"This endpoint is only for externally hosted domains."
}
}
Not available for externally hosted domains
Parameters
zone_id (numeric - inurl)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":[
{
"domain":"example.no",
"source":"@",
"target_url":"https://www.target-site.no",
"enabled":1,
"created_at":"2024-01-15 12:00:00"
},
{
"domain":"blog.example.no",
"source":"blog",
"target_url":"https://blog.target-site.no",
"enabled":1,
"created_at":"2024-02-20 14:30:00"
}
]
}
Error responses
// Externally hosted domain
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Redirects are not available for externally hosted domains."
}
}
Replaces the A records for the source name with an A record pointing to the redirect server. The source name must not have other A records (except the default parking A record), or any AAAA, CNAME or ALIAS records. A root (@) redirect only covers the domain itself; create a separate redirect with source "www" to redirect www as well.
Required parameters
zone_id (numeric - inurl)
target_url (string - valid URL, e.g. "https://example.com")
Optional parameters
source (string - subdomain or "@" for root, default: "@")
Example request body
{
"source":"@",
"target_url":"https://www.target-site.no"
}
Example return data
{
"meta":{
"status":201,
"status_message":"201 Created",
"message":"Redirect created successfully."
},
"data":{
"domain":"example.no",
"source":"@",
"target_url":"https://www.target-site.no"
}
}
Error responses
// DNS conflict
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"DNS conflict: '@' has an existing A record (192.0.2.10). Please remove it before adding a redirect."
}
}
// Redirect already exists
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"A redirect already exists for example.no. Delete it first or update instead."
}
}
// External DNS
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"This domain uses external nameservers. Redirects cannot be configured."
}
}
// Invalid URL
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid target URL format. Must be a valid URL (e.g. https://example.com)."
}
}
Required parameters
zone_id (numeric - inurl)
source (string - subdomain or "@" for root)
target_url (string - valid URL)
Example request body
{
"source":"@",
"target_url":"https://www.new-target.no"
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Redirect updated successfully."
}
}
The A record pointing to the redirect server is removed. For root (@) redirects, a www A record pointing to the redirect server is also removed.
Required parameters
zone_id (numeric - inurl)
source (string - query parameter, subdomain or "@" for root)
Example: DELETE /dns/zones/123/redirect?source=@
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Redirect deleted successfully."
}
}
Compatible with the dyndns2 protocol. The hostname must belong to a DNS zone on your account that uses Gigahost nameservers. The zone is resolved automatically from the hostname, so no zone ID is needed; the zone apex itself can also be updated. When the address has changed, all existing A (or AAAA) records for the hostname are replaced by a single record with a 60-second TTL for fast propagation. Records are only written when the address differs from the current one.
Authentication: HTTP Basic Auth with your Gigahost username (email) and password (see /authenticate above), or an API key sent as Authorization: Bearer. An API key or user needs read/write access to DNS; a key limited to specific zones can only update hostnames in those zones. Invalid credentials return HTTP 401 with a JSON body.
Required parameters
hostname (string - query parameter. FQDN to update, e.g. home.example.no. Comma-separated for multiple.)
Optional parameters
myip (string - query parameter. IP address to set. An IPv6 address here is treated as myipv6. If neither myip nor myipv6 is given, the client's source IP is used.)
myipv6 (string - query parameter. IPv6 address to set.)
Response codes (plain text, not JSON)
good 1.2.3.4 # IP updated successfully
nochg 1.2.3.4 # No change, IP already correct
nohost # Hostname not found on your account, zone not on Gigahost nameservers, or not allowed for this API key
notfqdn # Invalid or missing hostname
badauth # The user or API key does not have read/write access to DNS
dnserr # DNS server error
badagent # Invalid IP address provided
When updating multiple hostnames, one response code is returned per line. When both IPv4 and IPv6 are updated, the IPv4 address is shown.
Examples with curl
# Update with a specific IP
curl --user "[email protected]:password" \
"https://api.gigahost.no/api/v0/dns/dyndns?hostname=home.example.no&myip=1.2.3.4"
# Let the server detect your IP automatically
curl --user "[email protected]:password" \
"https://api.gigahost.no/api/v0/dns/dyndns?hostname=home.example.no"
# Update with IPv6
curl --user "[email protected]:password" \
"https://api.gigahost.no/api/v0/dns/dyndns?hostname=home.example.no&myipv6=2a03:94e0::1234"
# Update both IPv4 and IPv6
curl --user "[email protected]:password" \
"https://api.gigahost.no/api/v0/dns/dyndns?hostname=home.example.no&myip=1.2.3.4&myipv6=2a03:94e0::1234"
# Update multiple hostnames at once
curl --user "[email protected]:password" \
"https://api.gigahost.no/api/v0/dns/dyndns?hostname=home.example.no,vpn.example.no&myip=1.2.3.4"
# Using an API key instead of username and password
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://api.gigahost.no/api/v0/dns/dyndns?hostname=home.example.no"
ddclient (/etc/ddclient.conf)
protocol=dyndns2
ssl=yes
server=api.gigahost.no
script=/api/v0/dns/dyndns
[email protected]
password='your-password'
home.example.no
Synology NAS
Go to Control Panel > External Access > DDNS. Select «Customized» provider and configure:
Query URL: https://api.gigahost.no/api/v0/dns/dyndns?hostname=__HOSTNAME__&myip=__MYIP__
Username: your Gigahost email (e.g. [email protected])
Password: your Gigahost password
Hostname: home.example.no
QNAP NAS
Go to Network & Virtual Switch > DDNS. Select «Customized» and configure:
URL: https://api.gigahost.no/api/v0/dns/dyndns?hostname=%HOST%&myip=%IP%
Username: your Gigahost email
Password: your Gigahost password
Hostname: home.example.no
Generic router
Select «Custom» or «User-defined» as the Dynamic DNS provider and enter:
Server / Update URL: api.gigahost.no
Path: /api/v0/dns/dyndns
Protocol: dyndns2
Username: your Gigahost email
Password: your Gigahost password
Hostname: home.example.no
OPNsense / pfSense
Go to Services > Dynamic DNS and add a new entry:
Service type: Custom
Update URL: https://api.gigahost.no/api/v0/dns/dyndns?hostname=%h&myip=%i
Username: your Gigahost email
Password: your Gigahost password
Hostname: home.example.no
MikroTik RouterOS
/ip cloud set ddns-enabled=no
/system script add name=dyndns source={
/tool fetch url="https://api.gigahost.no/api/v0/dns/dyndns\
?hostname=home.example.no&myip=$ipaddr" \
user="[email protected]" password="your-password" \
mode=https dst-path=dyndns.txt
}
/system scheduler add name=dyndns-update interval=5m on-event=dyndns
This plugin automates the process of completing a dns-01 challenge by creating, and subsequently removing, TXT records using the Gigahost API. It supports single-domain, multi-domain, and wildcard certificates.
Installation: pypi.org/project/certbot-dns-gigahost
pip install certbot-dns-gigahost
Create a credentials file (e.g. ~/.secrets/certbot/gigahost.ini) containing your Gigahost API key. The key needs read/write access to DNS for the zones you request certificates for.
dns_gigahost_api_token=YOUR_API_KEY
Important: Protect your credentials file with restricted permissions:
chmod 600 ~/.secrets/certbot/gigahost.ini
--dns-gigahost-credentials (required): Path to the credentials INI file.
--dns-gigahost-propagation-seconds (optional): Seconds to wait for DNS propagation. Default: 120.
certbot certonly \
--authenticator dns-gigahost \
--dns-gigahost-credentials ~/.secrets/certbot/gigahost.ini \
-d example.com \
-d www.example.com
certbot certonly \
--authenticator dns-gigahost \
--dns-gigahost-credentials ~/.secrets/certbot/gigahost.ini \
-d example.com \
-d "*.example.com"
docker run --rm \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /var/lib/letsencrypt:/var/lib/letsencrypt \
certbot-dns-gigahost \
certonly \
--authenticator dns-gigahost \
--dns-gigahost-credentials /etc/letsencrypt/gigahost.ini \
--agree-tos \
--email "[email protected]" \
-d example.com
1. The plugin authenticates with the Gigahost API using your API key as a Bearer token.
2. It looks up the DNS zone for the domain being validated.
3. It creates a _acme-challenge TXT record with the validation token.
4. After verification, the plugin removes the TXT record automatically.
Renewal is automatic. No additional configuration is needed after the initial certificate issuance. Test with:
certbot renew --dry-run
Manage your account: company and contact details, users, access to other accounts, security (password / 2FA / SSH keys / passkeys), API keys, sub-clients (for partner accounts), data processing agreements, and account-level actions like top-up and closure.
Who can use what. Endpoints marked admin only require a session token (from /authenticate) for a user with the admin access level. Personal API keys and users with the user access level can never manage users, sub-clients, API keys, notification settings, the account email, top-ups, account closure or the activity log, whatever permissions they have. The other endpoints work for any user; for API keys and scoped users they need the account permission (r for GET, rw for changes). GET /account is always available. Sub-client logins get 403 on every /account endpoint.
Responses. Endpoints that only confirm success return an empty data array and the status in meta, sometimes with a message. Errors return the status code and a message in meta. Numbers read from the account are mostly returned as strings.
Includes company and contact details, notification preferences, SSH keys, the current user's passkeys and 2FA state, and (for admin sessions) the list of users and order history.
Parameters
{none}
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":{
"cust_id":"1111",
"cust_name":"Example AS",
"cust_address":"Example Road 1",
"cust_address2":"",
"cust_zipcode":"0150",
"cust_city":"Oslo",
"cust_province":"Oslo",
"cust_country":"Norway",
"cust_phone":"+47 00000000",
"cust_phone2":"",
"cust_email":"[email protected]",
"cust_company_no":"999999999",
"cust_billing_email":"[email protected]",
"cust_billing_email2":"",
"cust_newsletter":false,
"cust_incident":true,
"cust_bandwidth_notification":true,
"cust_last_login":"1712000000",
"cust_email_on_login":false,
"cust_notify_service_renewal":true,
"cust_partner":"0",
"contact_2fa_secret":"XXXXXXXXXXXXXXXX",
"contact_2fa":"0",
"contact_password_login_enabled":true,
"sshkeys":[
{
"key_id":"1",
"cust_id":"1111",
"key_name":"laptop",
"key_added":"1700000000",
"key_data":"ssh-ed25519 AAAA... user@host"
}
],
"passkeys":[
{
"passkey_id":"1",
"passkey_name":"YubiKey",
"created_at":"1700000000",
"last_used":"1712000000"
}
],
"contacts":[
{
"contact_id":"5",
"contact_name":"Jane Doe",
"contact_email":"[email protected]",
"contact_phone":"",
"contact_address":"",
"contact_zip":"",
"contact_city":"",
"contact_username":"[email protected]",
"contact_admin":"1",
"contact_access_level":"admin",
"contact_active":"1",
"contact_login_time":"1712000000",
"contact_login_ip":"192.0.2.1",
"contact_2fa":"1",
"contact_email_validated":"1"
}
],
"orders":[
{
"order_id":"1",
"order_number":"100001",
"order_product_price_as_annual":"0",
"order_date":"1700000000",
"order_contract_to":"0",
"order_billing_type":"monthly",
"order_billing_date":"1714600000",
"order_total":"99.00",
"order_billing_cycle":"1",
"order_status":"active",
"products":[
{
"op_id":"1",
"srv_id":"3523",
"product_id":"42",
"op_type":"server",
"product_alt_name":"",
"op_sum":"99.00",
"product_name":"VPS-Linux-1",
"srv_name":"web01"
}
]
}
]
}
}
contacts and orders are only included for admin sessions. contact_2fa_secret is the current user's authenticator secret, used to set up 2FA (see /account/2fa). It is empty once 2FA is enabled; after 2FA is disabled a new secret is returned. Session responses also contain a legacy api_key field that is not used for authentication. API keys never see contact_2fa_secret or api_key.
Newest first.
Parameters
{none}
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":[
{
"log_id":"12345",
"contact_id":"5",
"contact_name":"Jane Doe",
"contact_username":"[email protected]",
"log_timestamp":"1712000000",
"log_entry":"User [email protected] changed their password."
}
]
}
Send any subset of the fields below. Any other field returns 400 "Invalid request.", and HTML special characters (< > " ' &) are rejected. Address fields cannot be set to an empty value; cust_address2 and the billing emails can. Company name, organisation number, phone and the main account email cannot be changed here (use /account/email for the email, contact support for the rest).
Optional parameters
cust_address (string - body)
cust_address2 (string - body)
cust_zipcode (string - body)
cust_city (string - body)
cust_province (string - body)
cust_country (string - body)
cust_billing_email (string - body) - valid email or empty
cust_billing_email2 (string - body) - valid email or empty
Example request body
{
"cust_address":"Example Road 2",
"cust_zipcode":"0151",
"cust_billing_email":"[email protected]"
}
Returns 200 on success.
Error responses
// Field that cannot be edited
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid request."
}
}
// Empty required field
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Required field is missing: cust_city"
}
}
All five settings are written on every call. A field left out is turned off (0), so always send all of them.
Required parameters
cust_newsletter (0|1 - body) - product newsletter
cust_incident (0|1 - body) - service incident notifications
cust_bandwidth_notification (0|1 - body) - bandwidth threshold alerts
cust_email_on_login (0|1 - body) - email on every login
cust_notify_service_renewal (0|1 - body) - upcoming renewal reminders
Returns 200 on success.
An account can have several users, each logging in with their own email address. The access level decides what a user can do: admin has full access, user is limited by a permissions object (same format as API keys, see API Keys), and server only sees the servers assigned to them. The list of users is in contacts from GET /account.
Includes the user's profile, permissions, and the servers currently assigned and available for assignment. contact_permissions is a JSON-encoded string (or null).
Required parameters
id (numeric - inurl) - contact_id
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":{
"contact_id":"5",
"contact_name":"Jane Doe",
"contact_email":"[email protected]",
"contact_phone":"",
"contact_address":"",
"contact_zip":"",
"contact_city":"",
"contact_username":"[email protected]",
"contact_admin":"0",
"contact_access_level":"user",
"contact_permissions":"{\"servers\":{\"mode\":\"r\",\"all\":true}}",
"contact_active":"1",
"contact_login_time":"1712000000",
"contact_login_ip":"192.0.2.1",
"contact_2fa":"0",
"servers":[
{ "id":"1", "srv_id":"3523", "srv_name":"web01", "ip_address":"192.0.2.10" }
],
"servers_unassigned":[
{ "srv_id":"3524", "srv_name":"db01", "ip_address":"192.0.2.11" }
]
}
}
A setup link valid for 24 hours is emailed to the new user. Following it verifies the email address and emails a temporary password, which must be changed at the first login (see the password change step under /authenticate). The user cannot log in before that.
Required parameters
name (string - body) - display name, no HTML special characters
username (string - body) - email address, used to log in
accesslevel (string - body) - admin, user or server
Optional parameters
permissions (object - body) - only for accesslevel user; same format as API key permissions
Example request body
{
"name":"Jane Doe",
"username":"[email protected]",
"accesslevel":"user",
"permissions":{
"servers": { "mode":"rw", "all":false, "ids":[3523] },
"support": { "mode":"rw" }
}
}
Returns 200 on success.
Error responses
// Email already in use
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Email address is already in use."
}
}
// Invalid access level
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Access level is not valid."
}
}
// Malformed permissions object
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid permissions structure."
}
}
Editable fields: name, email address, access level, permissions and password. Setting a password logs the user out of all sessions. Changing the email address sends a verification email to the new address, and the user cannot log in until it is verified. The last admin of the account cannot be downgraded, and you cannot downgrade yourself. Changing the access level away from user clears the permissions.
Required parameters
id (numeric - inurl) - contact_id
contact_name (string - body)
contact_username (string - body) - email address
contact_access_level (string - body) - admin, user or server
Optional parameters
contact_password (string - body) - new password, at least 5 characters; weak passwords and passwords found in known data breaches are rejected
permissions (object - body) - only for access level user; replaces the whole permissions object
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Account has been updated."
},
"data":[]
}
Validation errors (missing fields, invalid email, invalid access level, too short password) return 403 with a message; conflicts such as an email already in use return 400.
The user's sessions and server assignments are removed. You cannot delete your own user.
Required parameters
id (numeric - inurl) - contact_id
Returns 200 on success, 404 if the user is not found.
Used for users with the server access level.
Required parameters
id (numeric - inurl) - contact_id
srv_id (numeric - body) - server to assign
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Server has been added to user."
},
"data":[]
}
The relation_id is the servers[].id field from GET /account/user/{id}.
Required parameters
id (numeric - inurl) - contact_id
relation_id (numeric - inurl) - assignment id
Returns 200 on success, 404 if the assignment is not found.
A user can be given access to other customers' accounts, for example a consultant working for several companies. The admin of the other account invites the user by email, the user accepts, and can then switch between the accounts with one login. Access to another account always works like the user access level, limited by the permissions in the invitation; it never includes the account category (no access to /account management of the other account). API keys cannot switch accounts.
For admin and user sessions.
Parameters
{none}
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":[
{ "cust_id":1111, "cust_name":"Example AS", "is_primary":true, "acl":"admin" },
{ "cust_id":2222, "cust_name":"Other Company AS", "is_primary":false, "acl":"user" }
]
}
Returns a new session token scoped to the chosen account. Use your own cust_id to switch back. The current token stays valid.
Required parameters
cust_id (numeric - body) - an account from GET /account/customers
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":{
"token":"0123456789abcdef0123456789abcdef",
"token_expire":1712086400,
"customer_id":"2222",
"contact_id":5,
"customer_name":"Other Company AS",
"contact_access_level":"user",
"delegated":true,
"customer_address":"Other Road 1",
"customer_zipcode":"5003",
"customer_city":"Bergen",
"customer_province":"Vestland",
"contact_language":"en",
"payment_automated":0,
"vat":1
}
}
Error responses
// No accepted access to that account
{
"meta":{
"status":403,
"status_message":"403 Forbidden",
"message":"You do not have access to this customer."
}
}
For admin and user sessions. status is pending or active.
Parameters
{none}
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":[
{
"access_id":"17",
"cust_id":"2222",
"permissions":{
"servers": { "mode":"rw", "all":true },
"support": { "mode":"rw" }
},
"status":"pending",
"created_at":"1712000000",
"accepted_at":null,
"cust_name":"Other Company AS",
"granted_by_name":"John Smith"
}
]
}
Must be called from a session on your own account, not while switched into another account.
Required parameters
id (numeric - inurl) - access_id from GET /account/invitations
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Invitation accepted."
},
"data":[]
}
Returns 404 if the invitation is not found and 400 if it is no longer pending.
Invitations that have not been accepted yet are not listed.
Parameters
{none}
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":[
{
"access_id":"17",
"contact_id":"88",
"permissions":{
"servers": { "mode":"rw", "all":true },
"support": { "mode":"rw" }
},
"status":"active",
"created_at":"1712000000",
"accepted_at":"1712003600",
"contact_name":"John Doe",
"contact_username":"[email protected]"
}
]
}
The email must belong to an active user of a different Gigahost account; that user is notified and must accept the invitation. The response is the same whether or not such a user exists. To add someone as a user of your own account instead, use POST /account.
Required parameters
email (string - body) - the user's login email
permissions (object - body) - same format as API key permissions; the account category is ignored
Example request body
{
"email":"[email protected]",
"permissions":{
"servers": { "mode":"rw", "all":false, "ids":[3523, 3524] },
"support": { "mode":"rw" }
}
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"If an account exists, an invitation was sent."
},
"data":[]
}
Required parameters
id (numeric - inurl) - access_id from GET /account/access
permissions (object - body) - replaces the whole permissions object; the account category is ignored
Returns 200 with message "Permissions updated.", or 404 if the grant is not found.
The admin of the account that issued the grant can remove it, and the invited user can remove (leave) their own access or decline a pending invitation. Must be called from a session on your own account, not while switched into another account.
Required parameters
id (numeric - inurl) - access_id
Returns 200 with message "Access removed.", 404 if not found, 403 if it is not your grant.
All other active sessions on the account are logged out; the session making the request stays logged in.
Required parameters
current (string - body) - current password
new (string - body) - new password
Returns 201 on success. Weak passwords and passwords found in known data breaches are rejected with 400 and a message explaining why.
Error responses
// Wrong current password
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Unable to verify current password."
}
}
Changes the account's main email address (cust_email). Login usernames are not affected; change those with PUT /account/user/{id}. Send email to start: a verification link valid for 24 hours is emailed to the new address. Then send the hash from that link to complete the change.
Required parameters (start)
email (string - body) - new email address
Required parameters (complete)
hash (string - body) - hash from the verification link
Returns 200 when the verification email is sent and 201 when the change is completed. Returns 400 "Email already exists." if another account uses the address, and 404 if the hash is unknown or expired.
Submit the hash from the verification email to mark the email address as verified and activate the user. No authentication is needed.
Required parameters
hash (string - body) - 32-character hex hash from the verification link
Returns 200 on success, 400 if the hash is invalid or already used.
To enable: add the secret from contact_2fa_secret (GET /account) or ga_secret (/authenticate) to an authenticator app (TOTP), then send a current code. Enabling 2FA logs out all other sessions on the account. Disabling also requires a valid code and generates a new secret, so the authenticator must be set up again before re-enabling.
Required parameters
type (string - body) - "enable" or "disable"
code (numeric - body) - current 6-digit code from your authenticator app
Returns 200 on success, 400 "Unable to validate code." for a wrong code, 404 for an unknown type.
Saved keys can be selected by key_id when deploying or reinstalling a server. Supported key types: ssh-ed25519, [email protected], ecdsa-sha2-nistp256/384/521, ssh-rsa, rsa-sha2-256, rsa-sha2-512 and ssh-dss.
Required parameters
name (string - body) - label for the key
data (string - body) - OpenSSH public key (e.g. "ssh-ed25519 AAAA... user@host")
Returns 200 on success; the new key and its key_id are listed in GET /account. Invalid keys return 400 "SSH-key invalid."
Servers that already have the key are not changed.
Required parameters
id (numeric - inurl) - key_id from GET /account
Returns 200 on success, 404 if the key is not found.
Passkeys are WebAuthn credentials bound to the Gigahost control panel, so this flow is meant for a browser. Call once with step: "begin" to receive the registration options (publicKey), pass them to the browser's WebAuthn API, then call again with step: "finish" and the authenticator response within two minutes.
Required parameters (begin)
step (string - body) - "begin"
Required parameters (finish)
step (string - body) - "finish"
clientDataJSON (base64url - body) - returned by the authenticator
attestationObject (base64url - body) - returned by the authenticator
Optional parameters (finish)
name (string - body) - label, max 64 characters (letters, digits, space, - _ .)
The finish step returns 200 with message "Passkey registered successfully.", or 400 if the challenge has expired or the registration fails.
If password login was turned off and fewer than two passkeys remain, password login is turned back on automatically and the response says so.
Required parameters
id (numeric - inurl) - passkey_id from GET /account
Example return data (password login re-enabled)
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Passkey deleted. Password login has been automatically re-enabled because fewer than two passkeys remain.",
"password_login_reenabled":true
},
"data":[]
}
With password login off, your user can only sign in with a passkey in the control panel, and /authenticate with a password is refused. Turning it off requires at least two registered passkeys and your password. A confirmation email is sent on every change. The current state is contact_password_login_enabled in GET /account.
Required parameters
enabled (0|1 - body) - 1 to allow password login, 0 for passkey-only
Optional parameters
password (string - body) - your current password, required when enabled is 0
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Password login disabled."
},
"data":[]
}
Error responses
// Fewer than two passkeys
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"At least two passkeys are required to disable password login."
}
}
// Missing or wrong password
{
"meta":{
"status":403,
"status_message":"403 Forbidden",
"message":"Password is invalid."
}
}
Required parameters
contact_language (string - body) - "no" or "en"
Returns 200 with message "Language updated.", or 400 for any other value.
No authentication is needed. Step 1 emails a reset link valid for one hour. Step 2 takes the hash from that link, sets a new random password, emails it to the user and logs the user out of all sessions. Works for account users (email) and sub-clients (GH-xxxxx username). No new link is sent while earlier links are still pending, and nothing is sent for disabled accounts or unverified email addresses.
Required parameters (step 1)
username (string - body) - login email or sub-client username
Required parameters (step 2)
stage (string - body) - "2"
hash (string - body) - hash from the reset link
Returns 200 in all normal cases; the response does not reveal whether the username exists or the hash was valid.
Personal API keys authenticate unattended integrations without exposing your password. Each key is independent of your interactive session and can be revoked at any time. A key acts as the user who created it. All API key endpoints are admin only and require a session token.
Granular permissions. Every key has a permissions object with up to eight categories: dns, servers (also covers /bgp), webhosting, deploy, racks, support (/tickets), billing and account. Each category has a mode of "r" (read-only: GET requests pass, everything else returns 403; the server power and rescue actions GET /servers/{id}/reboot, /on, /off and /rescue count as writes) or "rw" (read-write: all methods allowed). For the three resource categories (dns, servers, and webhosting), a key can additionally be limited to a specific list of resource IDs by setting all: false and listing the IDs in ids; all defaults to true. When limited this way, list endpoints filter their results, requests for other IDs return 403, and requests that would create a new resource return 403. Categories not present in the permissions object mean no access, and an unknown category or mode makes the whole object invalid. The other categories are global: no per-resource limit. The same permissions object is used for users with the user access level and for access to other accounts.
Example permissions object
{
"dns": { "mode":"rw", "all":false, "ids":[123, 456] },
"servers": { "mode":"r", "all":true },
"webhosting": { "mode":"rw", "all":true },
"deploy": { "mode":"r" },
"racks": { "mode":"r" },
"support": { "mode":"rw" },
"billing": { "mode":"r" },
"account": { "mode":"r" }
}
This key can read all servers, fully manage all webhosting accounts, manage only DNS zones 123 and 456, and read the deploy catalog and racks/support/billing/account data, plus create support tickets.
Token format. Authenticate the key by sending Authorization: Bearer flux_live_<64 hex chars> on every request. See the API Key Authentication section under /authenticate above.
Security model. The full secret is shown only at creation (and at rotation); after that the secret cannot be recovered. List and read responses only return the key_prefix. API keys cannot create, list, modify, rotate, or delete other API keys. An optional expires_at auto-revokes the key once reached, and every successful request updates last_used_at and last_used_ip. Revoked and expired keys are deleted, together with their usage log, 90 days later.
Secrets are never returned, only the prefix. Revoked and expired keys are not listed.
Parameters
{none}
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":[
{
"key_id":"1",
"key_label":"CI deployment",
"key_prefix":"flux_live_abc123def456",
"permissions":{
"dns": { "mode":"rw", "all":true },
"servers": { "mode":"r", "all":true }
},
"created_at":"1712000000",
"expires_at":"1740873600",
"last_used_at":"1712256000",
"last_used_ip":"192.0.2.1",
"status":"active",
"revoked_at":null,
"contact_id":"5"
}
]
}
Same fields as the list. Revoked and expired keys can also be read here (status is active, revoked or expired).
Required parameters
id (numeric - inurl) - key_id
Error responses
// Not found
{
"meta":{
"status":404,
"status_message":"404 Not Found",
"message":"API key not found."
}
}
Newest first. Each entry includes timestamp, source IP, method, path, query string, request body, response code, and response body. Useful for auditing and debugging integrations.
Required parameters
id (numeric - inurl) - key_id
Optional parameters
limit (numeric - query) - default 50, max 200
offset (numeric - query) - default 0
Request bodies are stored up to 4 KB and response bodies up to 16 KB; request_body_truncated and body_truncated are 1 when this has happened. Sensitive fields in request bodies (password, current, new, secret, code, token, totp, passphrase) are redacted before storage. The 500 most recent entries per key are kept.
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"total":1,
"limit":50,
"offset":0
},
"data":[
{
"log_id":"9001",
"request_time":"1712256000",
"request_ip":"192.0.2.1",
"request_method":"GET",
"request_path":"dns/zones",
"request_query":"",
"request_body":"",
"request_body_truncated":"0",
"response_code":"200",
"response_body":"{\"meta\":{...},\"data\":[...]}",
"body_truncated":"0"
}
]
}
The secret is shown only this once. Store it immediately.
Required parameters
label (string - body) - 1-100 characters, no HTML special characters
permissions (object - body) - granular permissions, see the section above; an empty object gives a key with no access
Optional parameters
expires_at (Unix timestamp - body) - must be in the future; the key auto-revokes when reached
Example request body
{
"label":"CI deployment",
"expires_at":1740873600,
"permissions":{
"dns": { "mode":"rw", "all":false, "ids":[123, 456] },
"servers": { "mode":"r", "all":true }
}
}
Example return data
{
"meta":{
"status":201,
"status_message":"201 Created",
"message":"API key created."
},
"data":{
"secret":"flux_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"prefix":"flux_live_xxxxxxxxxxxx",
"label":"CI deployment",
"expires_at":1740873600,
"permissions":{
"dns": { "mode":"rw", "all":false, "ids":[123, 456] },
"servers": { "mode":"r", "all":true }
}
}
}
The new key's key_id is not returned; find it with GET /account/apikeys.
Error responses
// Missing or oversized label
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Label is required (max 100 characters)."
}
}
// expires_at in the past
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Expiry must be in the future."
}
}
// Missing or malformed permissions object
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid permissions payload."
}
}
The previous secret stops working immediately. The new secret is returned once. Store it immediately. Only active keys can be rotated.
Required parameters
id (numeric - inurl) - key_id
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"API key rotated."
},
"data":{
"secret":"flux_live_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
"prefix":"flux_live_yyyyyyyyyyyy"
}
}
The secret and id are unchanged. At least one of label or permissions must be supplied. Only active keys can be edited.
Required parameters
id (numeric - inurl) - key_id
Optional parameters (send at least one)
label (string - body) - 1-100 characters
permissions (object - body) - replaces the entire permissions object
Returns 200 with message "API key updated.", 400 "No changes supplied." if neither field is sent, 404 if the key is not found or not active.
The key is denied from the next request. It can still be read with GET /account/apikeys/{id} until it is deleted 90 days later.
Required parameters
id (numeric - inurl) - key_id
Returns 200 with message "API key revoked.", 400 if the key is not active, 404 if not found.
Partner accounts can manage sub-clients: separate end-customer entities under the partner umbrella, each with their own login, optional direct billing from Gigahost, and assigned servers / domains / webhosting accounts. Sub-clients log in through /authenticate with their GH-xxxxx username and see only the resources assigned to them and their own direct invoices. All sub-client endpoints are admin only and require the account to have the partner feature enabled (cust_partner in GET /account); otherwise they return 403.
Newest first.
Parameters
{none}
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":[
{
"client_id":"10",
"client_name":"Kari Nordmann",
"client_email":"[email protected]",
"client_phone":"+47 00000000",
"client_company_name":"Acme AS",
"client_company_no":"999999999",
"client_address":"Acme Road 1",
"client_zip":"0150",
"client_city":"Oslo",
"client_country":"Norway",
"client_username":"GH-10010",
"client_active":"1",
"client_login_enabled":"1",
"client_invoice_direct":"0",
"client_billing_ehf":"0",
"client_2fa":"0",
"client_created":"1710000000",
"client_login_time":"1712000000",
"client_login_ip":"192.0.2.1"
}
]
}
The response includes the sub-client's profile (same fields as the list), the servers/domains/webhosting accounts currently assigned, and the resources available to assign. The id of each assigned resource is the relation_id used to unassign it.
Required parameters
id (numeric - inurl) - client_id
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":{
"client_id":"10",
"client_name":"Kari Nordmann",
"client_email":"[email protected]",
"client_company_name":"Acme AS",
"client_username":"GH-10010",
"client_active":"1",
"client_login_enabled":"1",
"client_invoice_direct":"0",
"servers":[
{ "id":"1", "srv_id":"3523", "srv_name":"web01", "ip_address":"192.0.2.10" }
],
"servers_unassigned":[
{ "srv_id":"3524", "srv_name":"db01", "ip_address":"192.0.2.11" }
],
"domains":[
{ "id":"1", "zone_id":"42", "zone_name":"example.no" }
],
"domains_unassigned":[
{ "zone_id":"43", "zone_name":"example.com" }
],
"webhosting":[
{ "id":"1", "hosting_id":"7", "domain":"acme.example", "package":"start" }
],
"webhosting_unassigned":[]
}
}
The username is generated as GH-<client_id + 10000>. If invoice_direct is 1, name, email, address, zip, city and country are required, and a company (company_name set) also needs a 9-digit organisation number; otherwise the request fails with status 422 and message invoice_direct_requires_details or invoice_direct_requires_orgno. If the billing customer cannot be created, the request fails with status 502 and support is notified.
Required parameters
name (string - body)
password (string - body) - at least 6 characters
Optional parameters
email (string - body)
phone (string - body)
company_name (string - body)
company_no (string - body) - 9 digits when invoice_direct is 1 and company_name is set
address (string - body)
zip (string - body)
city (string - body)
country (string - body)
login_enabled (0|1 - body) - default 1
invoice_direct (0|1 - body) - default 0; Gigahost invoices the sub-client directly
send_login (boolean - body) - default false; email the username and password to the sub-client (needs email and login_enabled 1)
Example return data
{
"meta":{
"status":201,
"status_message":"201 Created",
"message":"Sub-client created."
},
"data":{
"client_id":10,
"client_username":"GH-10010"
}
}
Send any subset of the fields; unknown fields are ignored. Turning client_invoice_direct on checks the billing details (using the new values where sent) with the same 422 errors as creation, and future invoices for the sub-client's assigned resources go to the sub-client. Turning it off sends future invoices to the partner again. Invoices already issued are not changed.
Required parameters
id (numeric - inurl) - client_id
Optional parameters
client_name (string - body)
client_email (string - body)
client_phone (string - body)
client_company_name (string - body)
client_company_no (string - body)
client_address (string - body)
client_zip (string - body)
client_city (string - body)
client_country (string - body)
client_active (0|1 - body)
client_login_enabled (0|1 - body)
client_invoice_direct (0|1 - body)
password (string - body) - at least 6 characters; replaces the sub-client's password
Returns 200 with message "Sub-client updated.", 404 if not found.
A new random password is set and emailed together with the username to client_email. Use this to onboard a sub-client or when they have lost their password.
Required parameters
id (numeric - inurl) - client_id
Returns 200 with message "Login credentials sent.", 400 if the sub-client has no email address, 404 if not found.
All resource assignments and the sub-client's sessions are removed. The resources themselves are not deleted; they stay on the partner account.
Required parameters
id (numeric - inurl) - client_id
Returns 200 with message "Sub-client deleted.", 404 if not found.
Required parameters
id (numeric - inurl) - client_id
srv_id (numeric - body) - server to assign
Returns 200 with message "Server assigned to sub-client.", 400 if the server is not found or already assigned, 404 if the sub-client is not found.
Required parameters
id (numeric - inurl) - client_id
relation_id (numeric - inurl) - servers[].id from GET /account/clients/{id}
Returns 200 on success, 404 "Assignment not found." otherwise.
Required parameters
id (numeric - inurl) - client_id
zone_id (numeric - body) - DNS zone to assign
Returns 200 with message "Domain assigned to sub-client.", 400 if the domain is not found or already assigned, 404 if the sub-client is not found.
Required parameters
id (numeric - inurl) - client_id
relation_id (numeric - inurl) - domains[].id from GET /account/clients/{id}
Returns 200 on success, 404 "Assignment not found." otherwise.
Required parameters
id (numeric - inurl) - client_id
hosting_id (numeric - body) - webhosting account to assign
Returns 200 with message "Webhosting assigned to sub-client.", 400 if the hosting account is not found or already assigned, 404 if the sub-client is not found.
Required parameters
id (numeric - inurl) - client_id
relation_id (numeric - inurl) - webhosting[].id from GET /account/clients/{id}
Returns 200 on success, 404 "Assignment not found." otherwise.
Newest first. data_types and affected_groups are JSON-encoded arrays (strings), and created_at is a date and time (YYYY-MM-DD HH:MM:SS).
Parameters
{none}
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":[
{
"dpa_id":"1",
"cust_id":"1111",
"data_types":"[\"personal_data\",\"ip_address\"]",
"affected_groups":"[\"employees\",\"customers\"]",
"signed_by":"Jane Doe",
"signed_ip":"192.0.2.1",
"created_at":"2026-01-15 10:30:00"
}
]
}
Decode the data field to get the PDF file.
Required parameters
id (numeric - inurl) - dpa_id
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":{
"filename":"Data processing agreement.pdf",
"data":"JVBERi0xLjQKJ..."
}
}
Returns 404 "DPA was not found." for an unknown id.
The DPA is signed in the name of the authenticated user, and the source IP is recorded. Not available while switched into another account.
Required parameters
data_types (array of strings - body) - categories of personal data covered, e.g. ["personal_data","ip_address","payment_info","usage_login"]
affected_groups (array of strings - body) - groups whose data is processed, e.g. ["employees","customers"]
HTML special characters in any element are rejected.
Example return data
{
"meta":{ "status":201, "status_message":"201 Created" },
"data":{
"dpa_id":2,
"message":"DPA has been created."
}
}
The agreement and its PDF are permanently removed from the account. Download the PDF first if you need a copy.
Required parameters
id (numeric - inurl) - dpa_id
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":{
"success":true,
"message":"DPA has been revoked."
}
}
Returns 404 "DPA was not found." for an unknown id.
Creates an invoice for the amount; the credit is added when it is paid. Pay it like any other invoice. For Norwegian customers the amount includes VAT.
Required parameters
currency (string - body) - "nok", "eur" or "usd" (lower case)
amount (integer - body) - amount in the chosen currency
Rules:
- Minimum amount is 50 NOK, 5 EUR or 5 USD.
- The credit balance plus the top-up may not exceed the account's maximum credit for that currency.
- At most five unpaid top-up invoices at a time.
- New accounts can only top up in NOK, with a limit on the total per period; the error message states the limit and what remains.
- Accounts under review or with ordering disabled cannot top up.
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Top-up invoice has been generated. Proceed with payment."
},
"data":[]
}
Error responses
// Below minimum
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Minimum top-up amount for NOK is 50."
}
}
// Too many unpaid top-ups
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"You can only have five unpaid top-up invoices in your account."
}
}
// Account not allowed to top up
{
"meta":{
"status":403,
"status_message":"403 Forbidden",
"message":"Your account is not permitted to create top-ups."
}
}
Irreversible. Deletes all stored payment cards, users, SSH keys, sessions, support tickets, orders and the activity log, unsubscribes the account from newsletters, and marks the account as terminated. The account cannot be reopened. A new account must be created if access is needed again.
The request only succeeds if the account has no servers, colocation racks, active S3 buckets, active orders, DNS zones, webhosting accounts or unpaid invoices. Each precondition returns 400 with a message naming what blocks the closure.
Parameters
{none}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Account has been closed."
},
"data":[]
}
Error responses
// Active services present
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Account has existing services (Servers)."
}
}
// Unpaid invoices present
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Account has unpaid invoices."
}
}
Manage your cloud servers (VPS) and dedicated servers: power, console, reinstall, one-click apps, snapshots, backups, ISO images, IP addresses, reverse DNS, firewall, statistics, upgrades and cancellation. All paths are under /servers/{id}, where {id} is the server's srv_id from GET /servers. The operating system and app catalogs used for reinstalls are under /reinstall.
POST and PUT requests take a JSON body. Personal API keys and users need the servers permission, either for all servers or for the specific server: read access for GET requests, read/write access for everything else. Requests for a server that is not on your account (or not in your permission scope) are refused with 400, 401, 403 or 405 depending on the endpoint. Some endpoints only apply to certain server types; the server's srv_type ("vps" or "dedicated") and srv_vps_type ("kvm", "lxc" or empty for dedicated servers) tell them apart.
Results are paginated with 100 servers per page, newest first. meta holds the paging information and account-wide counts (total, active, vps, dedicated) for the current search.
Optional parameters
search (string - query - matches server name, server ID, location or primary IP address)
page (numeric - query - page number, default 1)
Each server includes its operating system (os), IP addresses (ips), the order it is billed on (order), any pending cancellation (cancelled, null when none) and its datacenter (datacenter). Boolean flags: srv_status (online), srv_status_rescue, srv_status_install, srv_status_snapshot, srv_status_mount (ISO mounted), srv_suspended, srv_new, and the srv_feature_* flags that tell which features the server supports. srv_ram is in GB. For servers with a traffic allowance, bw_used, bw_unit and bw_cap show this month's usage: GB of outbound traffic when srv_bw_type is "quota", or the 95th percentile of outbound traffic in Mbps when it is "cdr". bw_is_hourly is true when the allowance accrues hourly (hourly-billed servers). When the server runs a one-click app, os.os_name is shown as the base operating system followed by the app name in parentheses.
The objects may contain additional fields not shown here. Only rely on the fields documented on this page.
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"page":1,
"per_page":100,
"total_pages":1,
"total":2,
"active":2,
"vps":1,
"dedicated":1
},
"data":[
{
"srv_id":"3523",
"cust_id":"19998",
"os_id":"72",
"dc_id":"2",
"srv_name":"web01.example.com",
"srv_label":"srv3523.gigahost.no",
"srv_hostname":"srv3523.gigahost.no",
"srv_type":"vps",
"srv_vps_type":"kvm",
"srv_location":"DC2",
"srv_status":true,
"srv_status_rescue":false,
"srv_status_install":false,
"srv_status_snapshot":false,
"srv_status_mount":false,
"srv_suspended":false,
"srv_new":false,
"srv_feature_mgmt":true,
"srv_feature_reinstall":true,
"srv_feature_snapshot":true,
"srv_feature_firewall":true,
"srv_feature_backups":false,
"srv_feature_unlimited_ipmi":0,
"srv_cores":"2",
"srv_ram":2,
"srv_bw":"1000",
"srv_bw_type":"quota",
"srv_date_created":"1530609706",
"srv_primary_ip":"192.0.2.24",
"os":{
"os_id":"72",
"os_name":"Ubuntu 24.04 LTS 64-bit",
"os_release":"ubuntu",
"os_dedicated_only":"0",
"os_minram":"0",
"os_custom_partition":"1",
"os_single_disk_only":"1",
"os_base_id":"0"
},
"ips":[
{
"ip_id":"7795",
"sub_id":"405",
"ip_v4v6":"ipv4",
"ip_address":"192.0.2.24",
"ip_reverse":"web01.example.com",
"ip_traffic_sum":"0",
"ip_pkts_sum":"0",
"ip_nullroute":"0",
"ip_routed_to":"0",
"ip_type":"primary",
"ip_netmask":"255.255.255.0",
"ip_gateway":"192.0.2.1"
}
],
"order":{
"order_id":"3081",
"order_number":"3976",
"order_date":"1528244467",
"order_billing_type":"recurring",
"order_billing_date":"06.07.2026",
"order_billing_cycle":"1",
"order_status":"active",
"order_payment_status":"1",
"order_total":"199.00",
"product_id":"2058",
"product_name":"KVM 2048",
"product_vm_cores":"2",
"product_vm_memory":"2",
"product_vm_storage":"40"
},
"cancelled":null,
"datacenter":{
"dc_id":"2",
"dc_name":"DC2",
"region_id":"1",
"region_name":"Norway"
},
"bw_is_hourly":false,
"bw_used":12.4,
"bw_unit":"GB",
"bw_cap":1000
}
]
}
data is an array with one server object. It has the same fields as the list, plus:
install_details - only while an install is running: root_password (empty when SSH keys were installed), date_started and sshkey (true when SSH keys were installed)
ipmi_session - the active KVM/IPMI session, or null (see POST /servers/{id}/ipmi)
management_session - the active web KVM session on servers with web-based management, or null
cpus, hdds, gpus - hardware
ips - IPv4 addresses, plus the server's primary IPv6 address (ip_v4v6 "ipv6", /118) when its network has IPv6. The IPv6 entry has the same ip_id as the IPv4 address it belongs to
subnets - IPv6 subnets assigned to the server
order - also includes hourly (rate_hourly, accrued_hours, accrued_cost, monthly_cap, currency, next_invoice) on hourly-billed orders
attacklogs - DDoS attacks detected against the server
activity_log - the server's activity log (log_id, log_entry, log_timestamp), newest first
nics - network interfaces with link status (ifOperStatus and ifAdminStatus as booleans), used by POST /servers/{id}/nic/{nic_id}
processes - process list, only for servers reporting through the monitoring agent
bw_used, bw_used_in, bw_used_out - this month's traffic. GB for srv_bw_type "quota"; for "cdr", bw_used is the 95th percentile in Mbps and bw_used_in/out are 0
location - rack placement for dedicated servers, empty otherwise
srv_bw_limit_action - what happens when the traffic allowance is exceeded (see POST /servers/{id}/bandwidth)
Required parameters
id (numeric - inurl - server ID)
Example return data (shortened)
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":[
{
"srv_id":"3523",
"srv_name":"web01.example.com",
"srv_type":"vps",
"srv_vps_type":"kvm",
"srv_status":true,
"srv_status_install":false,
"srv_status_upgrade":false,
"srv_suspended":false,
"srv_feature_backups":true,
"srv_cores":"2",
"srv_ram":2,
"srv_bw":"1000",
"srv_bw_type":"quota",
"srv_bw_limit_action":"none",
"srv_primary_ip":"192.0.2.24",
"os":{
"os_id":"72",
"os_name":"Ubuntu 24.04 LTS 64-bit",
"os_release":"ubuntu",
"dist_logo":"/images/os/ubuntu.png"
},
"cpus":[],
"hdds":[
{
"hdd_id":"1622",
"srv_id":"3523",
"hdd_manufacturer":"KVM",
"hdd_model":"",
"hdd_type":"SSD",
"hdd_size":"40",
"hdd_serial_number":""
}
],
"gpus":[],
"ips":[
{
"ip_id":"7795",
"sub_id":"405",
"ip_v4v6":"ipv4",
"ip_address":"192.0.2.24",
"ip_reverse":"web01.example.com",
"ip_reverse_v6":"",
"ip_routed_to":"0",
"ip_type":"primary",
"ip_netmask":"255.255.255.0",
"ip_gateway":"192.0.2.1"
},
{
"ip_id":"7795",
"sub_id":"405",
"ip_v4v6":"ipv6",
"ip_address":"2001:db8:0:2::24",
"ip_reverse":"",
"ip_reverse_v6":"web01.example.com",
"ip_type":"primary",
"ip_netmask":"/118",
"ip_routed_to":"0",
"ip_gateway":"2001:db8:0:2::1"
}
],
"subnets":[],
"order":{
"order_id":"3081",
"order_number":"3976",
"order_billing_type":"recurring",
"order_billing_date":"06.07.2026",
"order_status":"active",
"order_total":"199.00",
"product_name":"KVM 2048"
},
"attacklogs":[],
"activity_log":[
{
"log_id":"912345",
"log_entry":"Reboot of server #3523 successful.",
"log_timestamp":"1759650000"
}
],
"cancelled":null,
"nics":[],
"processes":[],
"ipmi_session":null,
"management_session":null,
"bw_used":12.4,
"bw_used_in":3.1,
"bw_used_out":12.4,
"location":[],
"datacenter":{
"dc_id":"2",
"dc_name":"DC2",
"region_name":"Norway"
},
"pkg_id":0
}
]
}
Changes srv_name, the name shown in the control panel. It does not change the hostname inside the operating system.
Required parameters
id (numeric - inurl - server ID)
name (string - body)
Example request body
{
"name":"web01.example.com"
}
Returns 200 on success. An empty name returns 400 "Server name cannot be empty."; a suspended server returns 401 "Server suspended. Unable to change name."
powerstate is true when the server is powered on and false when it is off or the state could not be read.
Required parameters
id (numeric - inurl - server ID)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"powerstate":true,
"timestamp":1530706429
}
}
Returns 200 when the reboot was carried out and 400 when it failed. A suspended server returns 403 "Server suspended, unable to perform power action."
Required parameters
id (numeric - inurl - server ID)
Returns 200 on success and 400 when it failed. A suspended server returns 403 "Server suspended, unable to perform power action."
Required parameters
id (numeric - inurl - server ID)
This is a hard power off, not a graceful shutdown. Returns 200 on success and 400 when it failed. A suspended server returns 403 "Server suspended, unable to perform power action."
Required parameters
id (numeric - inurl - server ID)
The server reboots into a Linux rescue system that runs from memory, so you can reach the disks to repair or copy data. The disks are not changed. The rescue system's root password is emailed to you, unless you pass SSH keys, in which case those keys are installed for root and no password is sent. srv_status_rescue is true while the server is in rescue mode. Returns 200 on success and 400 when it failed.
Required parameters
id (numeric - inurl - server ID)
Optional parameters
ssh_keys (string - query - comma separated SSH key IDs from your account, e.g. 12,15)
Only for VPS servers (srv_vps_type "kvm" or "lxc"). Returns a WebSocket URL and a ticket. Connect to {url}?t={ticket} using the WebSocket subprotocol "binary" and speak RFB (VNC) 3.8 over it; the console offers security type None, so no VNC password is needed. noVNC works as a client. The ticket is valid for 60 seconds and for one connection only; request a new one to reconnect.
Required parameters
id (numeric - inurl - server ID)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"url":"wss://console.gigahost.no/ws",
"ticket":"q3Vx9...-Rk2",
"expires":1759650060,
"type":"kvm"
}
}
Error responses
// Not a VPS
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Endpoint not supported for this type of server."
}
}
// Server is suspended
{
"meta":{
"status":403,
"status_message":"403 Forbidden",
"message":"Server suspended, unable to open console."
}
}
// The console could not be started
{
"meta":{
"status":502,
"message":"Unable to start the console right now, please try again later."
}
}
For dedicated servers with remote management (srv_feature_mgmt). Access is limited to the IP addresses and subnets you list in acl (IPv4, up to 10 entries). Sessions last 3 hours. expiry 0 gives a session without time limit and requires the unlimited IPMI add-on (srv_feature_unlimited_ipmi = 1).
Servers with classic IPMI return the session: kvm_ip_address, kvm_username and kvm_password to log in with, and kvm_expires (Unix time). Only one IPMI session can be active per server; end it with DELETE /servers/{id}/ipmi. Servers with web-based KVM management return kvm_address, token_hash and kvm_url instead; open kvm_url in a browser. If such a session already exists, the existing one is returned.
Required parameters
id (numeric - inurl - server ID)
acl (string - body - semicolon separated list of IPv4 addresses and/or subnets allowed to connect, e.g. "203.0.113.5;198.51.100.0/24")
expiry (numeric - body - 3 for a 3 hour session, 0 for no time limit)
Example request body
{
"acl":"203.0.113.5;198.51.100.0/24",
"expiry":3
}
Example return data (IPMI)
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"kvm_id":"12",
"srv_id":"3523",
"kvm_ip_address":"203.0.113.10",
"kvm_username":"xxxx",
"kvm_password":"xxxx",
"kvm_userid":"5",
"kvm_expires":"1530717076",
"kvm_in_use":"1"
}
}
Example return data (web KVM)
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"kvm_address":"kvmproxy.gigahost.no",
"token_hash":"5f2b8c0e9d6a4b1c8e7f3a2d1c0b9a87",
"kvm_url":"https://kvmproxy.gigahost.no/?srvid=3523&authtoken=5f2b8c0e9d6a4b1c8e7f3a2d1c0b9a87"
}
}
Error responses
// expiry missing or not 3 or 0
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Expiry is invalid."
}
}
// No valid IPs in acl
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"ACL is required when creating a management session."
}
}
// More than 10 entries in acl
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Maximum 10 IPs supported on ACL."
}
}
// A session is already open
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Server already has an active IPMI/BMC session."
}
}
// expiry 0 without the unlimited add-on
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Expiry is invalid, you do not have the unlimited package. Contact support."
}
}
// Server is suspended
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Server suspended, unable to create session."
}
}
Returns 200 when the session was removed. Returns 400 "Server does not have an active IPMI/BMC session." (or "...active management session." for web KVM) when there is nothing to end.
Required parameters
id (numeric - inurl - server ID)
Lists the active distributions. Use dist_id with GET /reinstall/distro/{dist_id} to list the operating system versions. One-click apps are listed separately with GET /reinstall/apps.
Parameters
none
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":[
{
"dist_id":"1",
"type_id":"1",
"dist_name":"AlmaLinux",
"dist_value":"almalinux",
"dist_logo":"/images/os/almalinux.png",
"dist_description":"",
"dist_active":"1"
}
]
}
Lists the active operating system versions of one distribution. Pass os_id to POST /servers/{id}/reinstall. Check the requirements before reinstalling: os_dedicated_only = 1 can only be installed on dedicated servers, os_minram is the minimum memory in GB (0 = none), os_custom_partition = 1 means a custom partition layout can be given, os_support_raid = 1 means software RAID is supported, os_single_disk_only = 1 means the OS is installed on a single disk, and os_slow_install = 1 means the install takes longer than usual.
Required parameters
dist_id (numeric - inurl - from GET /reinstall/distro)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":[
{
"os_id":"147",
"dist_id":"1",
"os_name":"AlmaLinux 9 64-bit",
"os_release":"almalinux",
"os_dist":"9",
"os_arch":"amd64",
"os_custom_partition":"1",
"os_single_disk_only":"0",
"os_support_raid":"1",
"os_dedicated_only":"0",
"os_minram":"0",
"os_slow_install":"0"
}
]
}
Same fields as GET /reinstall/distro/{dist_id}, plus os_limited_support (1 when support for this operating system is limited). data is empty when the os_id does not exist or is not active.
Required parameters
os_id (numeric - inurl)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"os_id":"147",
"dist_id":"1",
"os_name":"AlmaLinux 9 64-bit",
"os_release":"almalinux",
"os_dist":"9",
"os_arch":"amd64",
"os_custom_partition":"1",
"os_single_disk_only":"0",
"os_limited_support":"0",
"os_support_raid":"1",
"os_dedicated_only":"0",
"os_minram":"0",
"os_slow_install":"0"
}
}
All data on the server's disks is erased. os_id is an operating system from GET /reinstall/distro/{dist_id} or a one-click app from GET /reinstall/apps.
Dedicated servers and KVM servers are reinstalled over the network: the server reboots into the installer and the call returns as soon as the install has started. Follow it with GET /servers/{id}/install; srv_status_install on the server is true until the install has finished. LXC servers are rebuilt immediately and the call returns when the server is ready.
The response contains the new root password in root_passwd. When SSH keys were installed, root_passwd is empty and sshkey is true; log in with your key. Store the password: while the install runs it is also shown in install_details on GET /servers/{id}, but not after that. reboot is false if the server could not be rebooted into the installer automatically; reboot it yourself in that case.
When os_id is a one-click app, the server gets the app's base operating system and the app is installed on top of it at first boot. The response then also has app_run_id and app, with the app's address (url) and admin login (admin_user and admin_password). The admin password is only shown while the app installs: save it now. Follow the app install with GET /servers/{id}/app. Apps can be installed on KVM servers and dedicated servers, not on LXC servers, and the server must meet the app's os_minram, os_min_disk and os_dedicated_only requirements.
Required parameters
id (numeric - inurl - server ID)
os_id (numeric - body - operating system or app ID)
Optional parameters
hostname (string - body - server hostname. If it is missing or not a valid hostname, the server's primary IP address is used)
language (string - body - OS locale, e.g. en_US, nb_NO)
keyboard (string - body - keyboard layout, e.g. no, us)
timezone (string - body - e.g. Europe/Oslo)
ssh_keys (array of numeric - body - IDs of SSH keys on your account to install for root, up to 10. Keys that are not on your account are ignored)
key_id (numeric - body - a single SSH key ID. Older form of ssh_keys, ignored when ssh_keys is sent)
firstboot (string - body - URL-encoded shell script that runs once as root when the new system first boots. With an app, it runs after the app is installed)
app_domain (string - body - apps only: a domain name that points to the server. The app is set up on this domain with a Let's Encrypt certificate. Without it, the app is reached on the server's IP address)
app_email (string - body - apps only: email address for the Let's Encrypt certificate, and the admin login for apps that use an email address as username)
part_config (string - body - advanced: base64-encoded custom partitioning in the installer's native format, for operating systems with os_custom_partition = 1. Omit it to use the default layout)
part_early_command (string - body - advanced: base64-encoded commands run by the installer before partitioning)
part_late_command (string - body - advanced: base64-encoded commands run by the installer at the end of the install)
Example request body
{
"os_id":147,
"hostname":"web01.example.com",
"language":"en_US",
"keyboard":"no",
"timezone":"Europe/Oslo",
"ssh_keys":[12,15]
}
Example request body (one-click app)
{
"os_id":312,
"hostname":"cloud.example.com",
"language":"en_US",
"keyboard":"no",
"timezone":"Europe/Oslo",
"app_domain":"cloud.example.com",
"app_email":"[email protected]"
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Server install has been initiated.",
"reboot":true,
"root_passwd":"",
"sshkey":true
},
"data":[]
}
Example return data (one-click app)
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Server install has been initiated.",
"reboot":true,
"root_passwd":"xxxxxxxxxxxx",
"sshkey":false,
"app_run_id":845,
"app":{
"name":"Nextcloud",
"url":"https://cloud.example.com",
"admin_user":"admin",
"admin_password":"xxxxxxxxxxxxxxxx"
}
},
"data":[]
}
Example return data (LXC)
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Server install has been completed.",
"reboot":true,
"root_passwd":"xxxxxxxxxxxx",
"sshkey":false
},
"data":[]
}
Error responses
// os_id missing or not numeric: 400 without a message
// Unknown os_id
{
"meta":{
"status":404,
"status_message":"404 Not Found",
"message":"Operating system not found."
}
}
// Server is suspended
{
"meta":{
"status":401,
"status_message":"401 Unauthorized",
"message":"Server suspended. Unable to reinstall."
}
}
// App on an LXC server
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Apps can only be installed on KVM servers and dedicated servers."
}
}
// The install could not be started. message says why, for example:
// "This app is not available right now."
// "This app is only available on dedicated servers."
// "This app needs at least 2 GB of memory."
// "This app needs at least 20 GB of disk."
// "The domain for the app is not a valid domain name."
// "The email address for the app is not valid."
{
"meta":{
"status":401,
"status_message":"401 Unauthorized",
"message":"This app needs at least 2 GB of memory."
}
}
Available while a reinstall started with POST /servers/{id}/reinstall (or a new deploy) runs on a dedicated or KVM server. Light enough to poll every few seconds. Returns 404 when the server is not being installed, which is also what you get once the install has finished; srv_status_install on GET /servers/{id} is then false. Rescue boots have no progress.
Fields
step - the current stage, see below
progress - estimated percentage, 0 to 99 while installing and 100 when failed. It moves forward within a stage over time and never goes back
done, total - packages installed out of total during the "packages" stage when the installer reports a count, otherwise null
date_started - Unix time the install was started
step_started - Unix time the current stage began
stalled - true when the install has not moved on for a long time (at least 30 minutes). Check the server's console
failed - true when the installer reported that the install failed
Values of step, in order
waiting - the install is prepared and the server is (re)booting into the network installer
boot - the server has started booting from the network
loader - the installer is being loaded
starting - the installer has started and read its configuration
disks - partitioning and formatting the disks
os - installing the base system
packages - installing packages
configure - installing the boot loader and configuring the system
post - running the final post-install steps; the server then reboots into the new system
failed - the install failed (progress is 100 and failed is true)
Not every installer reports every stage, so stages can be skipped.
Required parameters
id (numeric - inurl - server ID)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"step":"packages",
"progress":71,
"done":412,
"total":980,
"date_started":1759649400,
"step_started":1759649710,
"stalled":false,
"failed":false
}
}
Error responses
// No install running
{
"meta":{
"status":404,
"status_message":"404 Not Found",
"message":"The server is not being installed."
}
}
Stops the server from booting into the installer again and sets it back to boot from its disk. It does not undo anything the installer has already done, so a partly installed server may not boot; start a new reinstall in that case. Not supported on LXC servers. Returns 200 on success.
Required parameters
id (numeric - inurl - server ID)
Error responses
// LXC server
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Install cancellation not supported on this type of server."
}
}
// Server is suspended
{
"meta":{
"status":401,
"status_message":"401 Unauthorized",
"message":"Server suspended. Unable to abort."
}
}
A one-click app is a fresh Debian install with the app installed and configured on top of it. Install one by passing its os_id to POST /servers/{id}/reinstall (or when deploying a new server), with the optional app_domain and app_email.
Fields
os_id - pass as os_id when installing
os_name - app name
os_logo - logo as a data URI (SVG, PNG or WebP)
os_app_description, os_app_description_no - description in English and Norwegian
os_app_category - category, e.g. "CMS", "Storage", "Developer tools"
os_app_note, os_app_note_no - login instructions shown with the credentials
os_minram - minimum memory in GB (0 = none)
os_min_disk - minimum disk size in GB (0 = none)
os_dedicated_only - 1 when the app can only be installed on dedicated servers
os_app_domain - 0: the app does not use a domain, 1: a domain is optional, 2: a domain is recommended
os_app_version - the app version installed by the latest successful test install (may be empty)
Parameters
none
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":[
{
"os_id":"312",
"os_name":"Nextcloud",
"os_logo":"data:image/svg+xml;base64,PHN2ZyB...",
"os_app_description":"Self-hosted file sync and sharing.",
"os_app_description_no":"Selvdrevet fildeling og synkronisering.",
"os_app_category":"Storage",
"os_app_note":"Log in with the admin user below and change the password.",
"os_app_note_no":"Log in med admin-brukeren under og bytt passordet.",
"os_minram":"2",
"os_min_disk":"20",
"os_dedicated_only":"0",
"os_app_domain":"2",
"os_app_version":"31.0.4"
}
]
}
Shows the latest app install on the server, as long as the server still runs that app. Returns 404 when the server has never had an app, or has since been reinstalled with something else.
The app is installed after the operating system, when the server first boots. While the operating system installs, use GET /servers/{id}/install; status stays "pending" until the app install starts.
Fields
app_run_id - ID of this app install
os_id, name, logo - the app
status - pending (waiting for the operating system install to finish), running, completed, failed, timeout (the install stopped reporting) or aborted (replaced by a newer install)
step - a short description of what the install is doing, or why it ended
progress - 0 to 100
domain - the app_domain given at install, or empty
url - where the app is reached
version - installed app version, once completed
admin_user - admin username (empty for apps without a login, e.g. Docker)
admin_password - only while status is pending or running, empty after that. When the install completes, the login is emailed to you and stored on the server in /root/app-info.txt
note, note_no - login instructions in English and Norwegian
date_created, date_completed - Unix time (date_completed is 0 until it ends)
Required parameters
id (numeric - inurl - server ID)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"app_run_id":845,
"os_id":312,
"name":"Nextcloud",
"logo":"data:image/svg+xml;base64,PHN2ZyB...",
"status":"completed",
"step":"Installed",
"progress":100,
"domain":"cloud.example.com",
"url":"https://cloud.example.com",
"version":"31.0.4",
"admin_user":"admin",
"admin_password":"",
"note":"Log in with the admin user below and change the password.",
"note_no":"Log in med admin-brukeren under og bytt passordet.",
"date_created":1759649400,
"date_completed":1759650720
}
}
Error responses
// No app on this server
{
"meta":{
"status":404,
"status_message":"404 Not Found",
"message":"No app has been installed on this server."
}
}
snap_state is "pending" while the snapshot is being created, "completed" when it is ready, "rollback" while the server is being rolled back to it and "deleting" while it is being removed. snap_time is Unix time.
Required parameters
id (numeric - inurl - server ID)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":[
{
"snap_id":"123",
"srv_id":"3523",
"snap_name":"Asdf1234",
"snap_display_name":"before-upgrade",
"snap_time":"1759649400",
"snap_state":"completed"
}
]
}
The snapshot includes the server's memory state. A server can have at most 3 snapshots, and requires srv_feature_snapshot. The snapshot is created in the background; follow snap_state with GET /servers/{id}/snapshots.
Required parameters
id (numeric - inurl - server ID)
name (string - body - descriptive name of snapshot)
Example request body
{
"name":"before-upgrade"
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Snapshot is currently being created.",
"snap_id":123
},
"data":[]
}
Error responses
// Server does not support snapshots
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Snapshot feature not supported."
}
}
// Already 3 snapshots
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Unable to create snapshot. Max number reached (3)."
}
}
Everything written to the server after the snapshot was taken is lost. The rollback runs in the background and can take up to 30 minutes; srv_status_snapshot is true and snap_state is "rollback" until it has finished.
Required parameters
id (numeric - inurl - server ID)
snap_id (numeric - inurl)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Server is currently being rolled back. Allow for up to 30 minutes for it to complete."
},
"data":[]
}
An unknown snap_id returns 400 "Unable to rollback. Snapshot not found."
The snapshot is removed in the background. snap_state is "deleting" until it disappears from the list.
Required parameters
id (numeric - inurl - server ID)
snap_id (numeric - inurl)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Snapshot is being removed. This can take some time."
},
"data":[]
}
An unknown snap_id returns 400 "Unable to delete. Snapshot not found."
Only for KVM servers. Automatic backups cost 25% of the server's price and are added to the server's billing. If the next invoice is more than 34 days away, an invoice for the remaining whole months is created and sent straight away. srv_feature_backups is true once backups are enabled.
Required parameters
id (numeric - inurl - server ID)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Backups enabled."
},
"data":[]
}
A server that is not a KVM server returns 400 "Backups only available for KVM servers."
Required parameters
id (numeric - inurl - server ID)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Backups cancelled."
},
"data":[]
}
Returns 400 "Backups not enabled." when backups are not enabled on the server.
date is Unix time and size is in bytes. volid is an opaque token that identifies the backup; pass it unchanged to the restore and file endpoints. Requires backups to be enabled.
Required parameters
id (numeric - inurl - server ID)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":[
{
"name":"Backup-3523-2026-10-05-020012",
"date":1759622412,
"size":4831838208,
"volid":"Zk1hT2x3...c3Q9"
}
]
}
Returns 400 "Backup feature not enabled." when backups are not enabled on the server.
The server is stopped and its disks are overwritten with the backup. Everything written after the backup was taken is lost. The restore runs in the background and the server starts again when it has finished. To get single files back instead, use the backup file endpoints below.
Required parameters
id (numeric - inurl - server ID)
volid (string - body - from GET /servers/{id}/backups)
Example request body
{
"volid":"Zk1hT2x3...c3Q9"
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Backup restore initiated."
},
"data":[]
}
Returns 400 "Invalid backup." for a volid that is not one of this server's backups, and 400 "Backup feature not enabled." when backups are not enabled.
Start at the root ("/"), which lists the disks and partitions in the backup, and descend by passing an entry's filepath back in. Each entry has filepath (base64 path to pass to this endpoint or to download), text (name), type (for example "d" for a directory, "f" for a file, "l" for a symbolic link, "v" for a disk or partition), leaf (true when it has no children) and, where known, size (bytes) and mtime (Unix time). The first request against a backup can take up to a couple of minutes while the backup is opened.
Required parameters
id (numeric - inurl - server ID)
volid (string - query - from GET /servers/{id}/backups, URL-encoded)
Optional parameters
filepath (string - query - base64 encoded path inside the backup, URL-encoded. Default is the root, "/")
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":[
{
"filepath":"L2RyaXZlLXNjc2kwLmltZy5maWR4L3BhcnQvMS9ldGM=",
"text":"etc",
"type":"d",
"leaf":false,
"mtime":1759600000
},
{
"filepath":"L2RyaXZlLXNjc2kwLmltZy5maWR4L3BhcnQvMS9ob3N0bmFtZQ==",
"text":"hostname",
"type":"f",
"leaf":true,
"size":18,
"mtime":1759000000
}
]
}
Error responses
// Not a KVM server
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"File restore only available for KVM servers."
}
}
// volid is not one of this server's backups
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid backup."
}
}
// filepath is not base64
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid path."
}
}
// The backup could not be opened
{
"meta":{
"status":502,
"message":"Could not read the backup. Please try again in a moment."
}
}
On success the response is the file itself, not JSON. Takes the same volid and filepath as GET /servers/{id}/backups/files, with filepath pointing at the file. Errors are returned as JSON, as for the file listing; a failed download returns 502 "Could not download the file. Please try again in a moment."
Required parameters
id (numeric - inurl - server ID)
volid (string - query - from GET /servers/{id}/backups, URL-encoded)
filepath (string - query - base64 encoded path of the file, URL-encoded)
ISOs belong to your account and can be mounted on any of your KVM servers. iso_state is "pending" (waiting to be fetched), "uploading", "completed" (ready to mount) or "failed". iso_size is in MB and iso_mounted is 1 while the ISO is mounted on a server.
Required parameters
id (numeric - inurl - server ID)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":[
{
"iso_id":"88",
"cust_id":"19998",
"iso_url":"https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-13.1.0-amd64-netinst.iso",
"iso_name":"debian-13.1.0-amd64-netinst.iso",
"iso_hash":"0c2f1a6e8b3d4f5a6b7c8d9e0f1a2b3c",
"iso_size":"754",
"iso_state":"completed",
"iso_mounted":"0"
}
]
}
The ISO is downloaded in the background; follow iso_state with GET /servers/{id}/isos. The URL must be a public http or https URL whose path ends in .iso. Query strings are dropped. Your account can hold at most 3 ISOs.
Required parameters
id (numeric - inurl - server ID)
url (string - body - URL of the ISO image)
Example request body
{
"url":"https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-13.1.0-amd64-netinst.iso"
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"ISO is being uploaded."
},
"data":[]
}
Returns 400 with message "URL is not valid.", "URL not an ISO." or "Max number reached (3)."
A mounted ISO cannot be deleted; dismount it first.
Required parameters
id (numeric - inurl - server ID)
iso_id (numeric - inurl)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"ISO has been deleted."
},
"data":[]
}
Returns 400 "ISO not found" or "ISO is currently mounted."
Attaches the ISO as a CD-ROM, makes it the first boot device and reboots the server. Use the console (POST /servers/{id}/console) to work with the installer. srv_status_mount is true while an ISO is mounted. The ISO must have iso_state "completed". Returns 200 on success.
Required parameters
id (numeric - inurl - server ID)
iso_id (numeric - body - from GET /servers/{id}/isos)
Example request body
{
"iso_id":88
}
Returns 400 "ISO not valid." when iso_id is not numeric and 404 "ISO was not found." when it is not one of your ISOs.
Ejects the ISO, sets the server to boot from its disk again and reboots it. Returns 200 on success.
Required parameters
id (numeric - inurl - server ID)
Sets the reverse DNS (PTR) of one of the server's IP addresses, or delegates the reverse zone of an IPv6 subnet to your own name servers. Hostnames must be valid domain names, not IP addresses; a trailing dot is removed. Send an empty dns to clear it. ip_id and sub_id come from ips and subnets on GET /servers/{id}.
Required parameters
id (numeric - inurl - server ID)
For one IP address (IPv4, or the server's primary IPv6 address)
ip_id (numeric - body)
v4v6 (string - body - "ipv4" or "ipv6". With "ipv6", ip_id is the ip_id of the IPv6 entry, which is the same as that of its IPv4 address)
dns (string - body - hostname, e.g. server.example.com)
For an IPv6 subnet (name server delegation)
sub_id (numeric - body - subnet ID)
dns (string - body - first name server, e.g. ns1.example.com)
dns2, dns3, dns4, dns5 (string - body - optional, more name servers)
Example request body (IPv4)
{
"ip_id":7795,
"v4v6":"ipv4",
"dns":"web01.example.com"
}
Example request body (IPv6 subnet)
{
"sub_id":2236,
"dns":"ns1.example.com",
"dns2":"ns2.example.com"
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Reverse has been updated."
},
"data":[]
}
Returns 400 "Submitted data is not a valid hostname or NS." for an invalid name, and 400 without a message when neither ip_id nor sub_id is given or v4v6 is missing.
Adds one additional IPv4 address to the server per request and adds it to the server's order. Pass "l2" for a layer 2 IP in the same network as the primary IP (configure it on the server with the netmask and gateway shown in ips), or "l3" for a routed (failover) IP that is routed to the server's primary IP and can be moved between your servers with PUT /servers/{id}/ipv4/{ip_id}. Routed IPs are only available in Norway. A server can have at most 5 additional IPs. On monthly orders an invoice for the remaining whole months is created if the next invoice is more than 34 days away; hourly orders are billed by the hour.
Not available to sub-client logins.
Required parameters
id (numeric - inurl - server ID)
ip_type (string - body - "l2" or "l3")
num_ips (numeric - body - must be present and numeric; one IP is added per request)
Example request body
{
"ip_type":"l3",
"num_ips":1
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Additional routed IPv4 has been added.",
"ip_id":"9012",
"ip_address":"203.0.113.77"
},
"data":[]
}
Error responses
// ip_type not l2/l3, or num_ips missing
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid data received."
}
}
// Already 5 additional IPs
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Max number of additional IPs reached. Contact support."
}
}
// Routed IP outside Norway
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Failover IPs not available in this region. Contact support."
}
}
// No free IPs ("No more failover IPs available. Contact support." for l3)
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"No more layer 2 IPs available. Contact support."
}
}
// The server has no active order
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Order for this server was not found, uanble to add IP."
}
}
Removes the IP and its reverse DNS from the server and takes it off the order. Routed IPs are unrouted first. Not available to sub-client logins.
Required parameters
id (numeric - inurl - server ID)
ip_id (numeric - inurl)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"IP 203.0.113.77 was removed from the server."
},
"data":[]
}
Returns 400 "Resource not found on server. Contact support." when the IP is not on the server.
Moves an additional, routed (layer 3) IP from one of your servers to another. Only layer 3 IPs can be moved; layer 2 IPs cannot. Both servers must belong to your account and be in the same region. The destination server must already have a primary IP, an active order and fewer than 5 additional IPs. The IP's billing line moves to the destination server's order and follows that order's billing model and currency. Not available to sub-client logins.
Required parameters
id (numeric - inurl - source server)
ip_id (numeric - inurl - the IP to move)
target_srv_id (numeric - body - destination server)
Example request body
{
"target_srv_id":456
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"IP has been moved.",
"ip_id":"789",
"target_srv_id":456
},
"data":[]
}
Error responses
// Invalid or same destination server
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid destination server."
}
}
// IP is not an additional IP on the source server
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"IP not found on this server."
}
}
// IP is layer 2, not routed
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Only routed (L3) IPs can be moved."
}
}
// Destination server is in a different region
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Destination server must be in the same region as the IP."
}
}
// Destination server has no primary IP
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Destination server has no primary IP."
}
}
// Destination server is at the additional IP limit
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Destination server has reached the maximum number of additional IPs. Contact support."
}
}
// Destination server has no active order
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Destination server has no active order."
}
}
// You do not own the destination server
{
"meta":{
"status":403,
"status_message":"403 Forbidden",
"message":"Access denied."
}
}
Disabling the port takes the interface offline at the switch, for example to isolate a compromised server. nic_id comes from nics on GET /servers/{id}, where ifAdminStatus shows whether the port is enabled. Not every network supports this; unsupported ports return 400 "Operation not supported. Please contact support."
Required parameters
id (numeric - inurl - server ID)
nic_id (numeric - inurl)
action (string - body - "enable" or "disable")
Example request body
{
"action":"disable"
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Switch port has been disabled."
},
"data":[]
}
Returns 404 "Switch port associated with network interface was not found." for an unknown nic_id, 400 "Server is suspended. Unable to change switch port status." for a suspended server, and 400 without a message for any other action.
Only available for VPS servers (KVM and LXC). Rules are returned sorted ascending by position, which is the order they are evaluated in.
Required parameters
id (numeric - inurl - server ID)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"options":{
"enable":true,
"policy_in":false,
"policy_out":true,
"dhcp":1,
"ipfilter":0,
"macfilter":1,
"ndp":1,
"radv":0,
"log_level_in":"nolog",
"log_level_out":"nolog"
},
"rules":[
{
"pos":0,
"type":"out",
"action":"DROP",
"source":"",
"dest":"",
"proto":"tcp",
"dport":"25",
"enable":1,
"log":"nolog",
"ipversion":4,
"comment":"SMTP blocked by default per TOS"
},
{
"pos":1,
"type":"in",
"action":"ACCEPT",
"source":"192.0.2.0/24",
"dest":"",
"proto":"tcp",
"dport":"22",
"enable":1,
"log":"nolog",
"ipversion":4,
"comment":"SSH from office"
}
]
}
}
policy_in and policy_out are returned as booleans, where true means ACCEPT and false means DROP. enable is false when the firewall is turned off. source and dest are empty strings when the rule applies to any address.
Error responses
// Server is not a VPS on your account
{
"meta":{
"status":401,
"status_message":"401 Unauthorized",
"message":"401 Unauthorized"
}
}
// API key without read permission for this server
{
"meta":{
"status":403,
"status_message":"403 Forbidden",
"message":"You do not have permission for this operation."
}
}
// The firewall could not be loaded
{
"meta":{
"status":502,
"message":"The firewall could not be loaded right now, please try again later."
}
}
This is a full replace, not a patch. Every existing rule is deleted and the rules you submit are installed in their place, so always send the complete ruleset. Sending an empty rules array removes all rules. There is no endpoint for editing a single rule. If any rule is rejected, the previous rules are put back and nothing is changed.
Rules are evaluated in the order they appear in the array.
default_action sets the default policy for incoming traffic only. The default policy for outgoing traffic is always ACCEPT and cannot be changed.
On servers where outgoing SMTP is blocked by default, the outgoing DROP rules for port 25 and 465 must be included in every request and the firewall cannot be disabled. Rules with the comment "SMTP blocked by default per TOS" (as returned by GET) are always moved to the top of the ruleset. Contact support if you need SMTP opened.
Required parameters
id (numeric - inurl - server ID)
default_action (boolean - body - true for ACCEPT, false for DROP)
enable (boolean - body - true to enable the firewall, false to disable it)
rules (array of objects - body - the complete ruleset)
Each rule object takes
type (string - "in" or "out")
action (string - "ACCEPT" or "DROP")
proto (string - tcp, udp, icmp, etc.)
dport (numeric or string - destination port, list or range, e.g. 443, "80,443" or "8000:8100")
sport (numeric or string - optional, source port, list or range)
source (string - source address or subnet, empty for any)
dest (string - destination address or subnet, empty for any)
enable (numeric - 1 to enable the rule, 0 to disable it)
comment (string - free text description)
default_action and enable must be sent as real JSON booleans. Values such as 1 or "true" are rejected. Whitespace in ports and addresses is removed. pos and ipversion from GET are ignored, and logging is always off.
Example request body
{
"enable":true,
"default_action":false,
"rules":[
{
"type":"out",
"action":"DROP",
"proto":"tcp",
"dport":25,
"source":"",
"dest":"",
"enable":1,
"comment":"SMTP blocked by default per TOS"
},
{
"type":"out",
"action":"DROP",
"proto":"tcp",
"dport":465,
"source":"",
"dest":"",
"enable":1,
"comment":"SMTP blocked by default per TOS"
},
{
"type":"in",
"action":"ACCEPT",
"proto":"tcp",
"dport":22,
"source":"192.0.2.0/24",
"dest":"",
"enable":1,
"comment":"SSH from office"
}
]
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":[]
}
The applied ruleset is not returned. Use GET /servers/{id}/firewall to read back the result.
Error responses
// Server does not support the firewall feature
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Firewall feature not supported."
}
}
// default_action is missing or not a boolean
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Invalid firewall rules. Default firewall state can only be true or false (ACCEPT/DROP)."
}
}
// enable is missing or not a boolean
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Firewall state can only be true or false (Enabled/Disabled)."
}
}
// Server is not a VPS
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Firewall is not supported."
}
}
// A rule was rejected (numbered from 1, in the order sent). Nothing was changed
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Firewall rule 3 was rejected (invalid dport). No changes were saved."
}
}
// Trying to disable the firewall while SMTP is blocked by default
{
"meta":{
"status":404,
"status_message":"404 Not Found",
"message":"Unable to disable firewall, due to default SMTP blocking. Contact support to review for opening SMTP."
}
}
// The mandatory port 25/465 rules are missing or overwritten
{
"meta":{
"status":404,
"status_message":"404 Not Found",
"message":"Unable to delete rules for port 25/465 or overwrite them, due to default SMTP blocking. Contact support to review for opening SMTP."
}
}
// The firewall could not be updated right now
{
"meta":{
"status":502,
"message":"Unable to update firewall rules. Please try again later."
}
}
Rates are in Mbps, averaged over each step: 300 seconds for spans up to 2 days, 3600 seconds up to 60 days, and 86400 seconds (daily) beyond that. Timestamps are local time (Europe/Oslo). The series ends at the last measured point.
Required parameters
id (numeric - inurl - server ID)
Optional parameters
range (string - query - "day", "week", "month", "year" or "custom". Default "day")
from (string - query - YYYY-MM-DD, required with range=custom)
to (string - query - YYYY-MM-DD, required with range=custom)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"timeseries":[
{
"timestamp":"2026-10-05 10:00:00",
"egress_mbps":12.5321,
"ingress_mbps":3.1022
},
{
"timestamp":"2026-10-05 10:05:00",
"egress_mbps":11.9810,
"ingress_mbps":2.8874
}
],
"step":300,
"from":"2026-10-04 10:02:11",
"to":"2026-10-05 10:02:11",
"range":"day"
}
}
Returns 400 "Invalid range. Must be day, week, month, year, or custom." or "Custom range requires from and to parameters (YYYY-MM-DD)."
current_* is the latest 5 minute average in Mbps. mtd_* are this calendar month's totals in GB. p95_* are this month's 95th percentile rates in Mbps. For hourly-billed servers with a traffic quota, the allowance builds up over a 720 hour month: accrued_allowance_gb is the allowance so far and hours_accrued the hours counted.
Required parameters
id (numeric - inurl - server ID)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"current_egress_mbps":12.53,
"current_ingress_mbps":3.1,
"mtd_egress_gb":40.12,
"mtd_ingress_gb":9.87,
"mtd_total_gb":49.99,
"p95_egress_mbps":28.4,
"p95_ingress_mbps":7.15,
"billing_month":"2026-10-01",
"is_hourly":false,
"accrued_allowance_gb":0,
"hours_accrued":0,
"period_hours":720
}
}
Returns PNG images, base64 encoded, for the last day, week, month and year. Returns 201 with empty data when no graph is available for the server.
Required parameters
id (numeric - inurl - server ID)
Optional parameters
type (string - inurl - "port_bits" (traffic, default), "port_upkts" (packets), "port_percent" (utilisation in percent) or "port_errors" (errors))
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"graph_day":"img-data (base64)",
"graph_week":"img-data (base64)",
"graph_month":"img-data (base64)",
"graph_year":"img-data (base64)"
}
}
Only has data for servers that report through the Gigahost monitoring agent. Each series covers roughly the last day, newest first, with a matching timestamp array ("YYYY-MM-DD HH:MM:SS"). data is empty when there is nothing to show.
Series per type
cpu - usage, user, nice, system, iowait, irq, softirq, steal, guest (percent)
load - onemin, fivemin, fifteenmin (load average)
disk - disks: one array per mount point with percent used
network - in, out (Mbps on the default interface; out is negative)
memory - free, caches, usage (MB)
Required parameters
id (numeric - inurl - server ID)
type (string - inurl - "cpu", "load", "disk", "network" or "memory")
Example return data (load)
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"onemin":["0.12","0.20"],
"fivemin":["0.10","0.14"],
"fifteenmin":["0.08","0.09"],
"timestamp":["2026-10-05 10:05:00","2026-10-05 10:00:00"]
}
}
"none" only sends you a notice (overage may be billed), "stop" powers the server off, and "suspend" suspends the server for the rest of the month. The current setting is srv_bw_limit_action on GET /servers/{id}. Returns 200 on success.
Required parameters
id (numeric - inurl - server ID)
action (string - body - "none", "stop" or "suspend")
Example request body
{
"action":"stop"
}
Other values return 400 "Bandwidth action can only be either none, suspend, limit or stop." ("limit" is not accepted.)
Only for KVM servers. Lists larger packages in the same product line that are available in the server's region and that have capacity, in your order's currency. product_vm_memory and product_vm_storage are in GB. rate_monthly is the monthly price in currency_code, excluding VAT.
Required parameters
id (numeric - inurl - server ID)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":[
{
"product_id":"2059",
"product_name":"KVM 4096",
"product_vm_cores":"4",
"product_vm_memory":"4",
"product_vm_storage":"50",
"product_vm_bw":"2000",
"product_vm_bw_type":"quota",
"region_id":"1",
"rate_monthly":"299.00",
"currency_code":"NOK",
"prefix":"kr"
}
]
}
Error responses (all 404)
// "Servers order was not found. Unable to upgrade. Contact support."
// "Unable to upgrade server. Was not able to locate server package. Contact support."
// "Upgrade unavailable in this region."
// "Unable to upgrade server due to product or service being out of stock."
{
"meta":{
"status":404,
"status_message":"404 Not Found",
"message":"Upgrade unavailable in this region."
}
}
Adds CPU cores and memory, grows the disk to the package size and reboots the server to apply the changes. The disk is grown, but the partitions and file systems inside the server are not; extend them yourself. Servers with snapshots cannot be upgraded. Downgrades are not possible. Monthly orders: if the next invoice is more than 34 days away, an invoice for the price difference for the remaining whole months is created and sent. Hourly orders: the new hourly rate applies from the upgrade. Returns 200 on success.
Required parameters
id (numeric - inurl - server ID)
product_id (numeric - body - from GET /servers/{id}/upgrade)
Example request body
{
"product_id":2059
}
Error responses
// product_id missing or not numeric: 400 without a message
// Not a KVM server
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Upgrade is only available for cloud servers."
}
}
// The server has snapshots
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Unable to upgrade server with existing snapshots. Remove and try again."
}
}
// Package not offered for this server
{
"meta":{
"status":404,
"status_message":"404 Not Found",
"message":"Upgrade unavailable due to service being out of stock."
}
}
// Also 404: "Upgrade unavailable in this region.", "Upgrade unavailable in your currency. Contact support.",
// "Servers order was not found. Unable to upgrade. Contact support."
By default the server keeps running until the end of the paid period and is terminated on termination_date (Unix time). Hourly-billed servers are always terminated right away and their final hours are billed on the next monthly invoice. With early_termination set to 1 the server is terminated right away and its data is deleted; the paid period is not refunded. termination_date 0 means immediate termination. Servers under a minimum contract cannot be cancelled before the contract ends. The pending cancellation is shown in cancelled on GET /servers/{id}.
Not available to sub-client logins.
Required parameters
id (numeric - inurl - server ID)
Optional parameters
reason (string - body - why you are cancelling)
early_termination (numeric - body - 1 to terminate and delete the server immediately, default 0)
Example request body
{
"reason":"Moving to a larger server",
"early_termination":0
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Server has been cancelled.",
"termination_date":1762297200
},
"data":[]
}
Error responses
// Under contract
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Unable to cancel server, still under contract until 01.03.2027."
}
}
// Already cancelled
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Server has already been cancelled. It will be terminated on 06.11.2026."
}
}
// No active order for the server
{
"meta":{
"status":404,
"status_message":"404 Not Found",
"message":"No order was found. Contact support."
}
}
Create, read and answer support tickets, including file attachments.
Read operations need a token or API key with read access to support; creating, replying, uploading and closing need read-write access to support. Not available to sub-client logins.
Parameters
{none}
status is open or closed. created_at and last_reply_at are Unix timestamps.
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":[
{
"ticket_id":"4821937",
"subject":"Reverse DNS for my server",
"created_at":"1759650000",
"last_reply_at":"1759660000",
"status":"open"
}
]
}
Required parameters
ticket_id (numeric - inurl - ticket id)
In replies, operator is true for messages from our support staff and false for your own. created is a Unix timestamp. Each message has the files attached to it, and files at the top level lists every file on the ticket. For a file, uploader is customer, staff or email, inline_ok tells whether it can be shown in a browser, has_thumb whether a thumbnail is available, and rejected / reject_reason mark a file that was refused and cannot be downloaded. Older attachments have a file_id that starts with L. Returns 404 if the ticket is not found.
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":{
"ticket":{
"ticket_id":"4821937",
"subject":"Reverse DNS for my server",
"created_at":"1759650000",
"last_reply_at":"1759660000",
"status":"open"
},
"replies":[
{
"message":"Hi, this has now been updated.",
"created":"1759660000",
"operator":true,
"files":[]
},
{
"message":"Please set the reverse DNS for 192.0.2.24 to mail.example.no.",
"created":"1759650000",
"operator":false,
"files":[
{
"file_id":3310,
"name":"screenshot.png",
"mime":"image/png",
"size":48211,
"is_image":true,
"has_thumb":true,
"inline_ok":true,
"rejected":false,
"reject_reason":"",
"uploader":"customer",
"created":1759650000
}
]
}
],
"files":[
{
"file_id":3310,
"name":"screenshot.png",
"mime":"image/png",
"size":48211,
"is_image":true,
"has_thumb":true,
"inline_ok":true,
"rejected":false,
"reject_reason":"",
"uploader":"customer",
"created":1759650000
}
]
}
}
Required parameters
ticket_id (numeric - inurl - ticket id)
file_id (numeric or string - inurl - file_id from the ticket's files)
Optional parameters
disposition (string - query) - inline to display the file in the browser instead of downloading it (only honoured for files where inline_ok is true)
variant (string - query) - thumb to get the thumbnail (for files where has_thumb is true)
Returns 404 if the ticket or file is not found, or if the file was rejected.
Send the files as multipart/form-data in the field files[]. Pass the returned file_id values in file_ids when you create the ticket or reply. Limits: 20 MB per file, 5 files per upload and 25 files per ticket. Accepted types: jpg, png, gif, webp, bmp, tif, heic, pdf, txt and csv. Uploaded files that are never attached to a ticket are removed after a while.
Required parameters
files[] (file - multipart form field, one or more)
Example request
curl -X POST -H "Authorization: Bearer {token}" -F "files[][email protected]" -F "files[][email protected]" https://api.gigahost.no/api/v0/tickets/files
Accepted files are returned in files and refused ones in errors with the reason. If no file could be stored, status 400 is returned with the first reason in message.
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":{
"files":[
{ "file_id":3310, "name":"screenshot.png", "size":48211, "mime":"image/png", "is_image":true }
],
"errors":[
{ "name":"archive.zip", "message":"File type not allowed (application/zip). Accepted: jpg, png, gif, webp, bmp, tif, heic, pdf, txt, csv." }
]
}
}
HTML tags are stripped from subject and message. You can have at most 10 open tickets at a time.
Required parameters
subject (string - body)
message (string - body)
Optional parameters
srv_id (numeric - body - the server the ticket is about; ignored if it is not one of your servers)
file_ids (array of numeric - body - files uploaded with POST /tickets/files)
Example request body
{
"subject":"Reverse DNS for my server",
"message":"Please set the reverse DNS for 192.0.2.24 to mail.example.no.",
"srv_id":3523,
"file_ids":[3310]
}
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":{
"message":"Ticket created.",
"ticket_id":4821937
}
}
Returns 400 without a message if subject or message is empty, and 400 with "Maximum number of open tickets reached." when the limit is reached.
Replying to a closed ticket reopens it. A reply may consist of attachments only.
Required parameters
ticket_id (numeric - inurl - ticket id)
reply (string - body) and/or file_ids (array of numeric - body - files uploaded with POST /tickets/files)
Example request body
{
"reply":"Thanks, that works.",
"file_ids":[]
}
Returns status 200 with no data on success.
// 400 - "Reply cannot be empty."
// 400 - "Ticket was not found or you do not have access to it."
Invoices, orders, payment methods, saved cards, account credit and pay-as-you-go (hourly) usage.
Read operations need a token or API key with read access to billing; paying, changing the payment method and managing cards need read-write access to billing. Sub-client logins can only use GET /billing (which then returns just their own invoices) and GET /billing/invoice/{inv_md5}.
Amounts are excluding VAT unless stated otherwise. Dates are Unix timestamps.
Parameters
{none}
Response fields:
invoices - all your invoices, newest first. inv_md5 is the key used to download or remove an invoice, inv_id the id used to pay it. inv_total is excluding VAT, inv_vat the VAT rate in percent and inv_total_vat the total including VAT. inv_kid is the payment reference (KID) for bank transfers. inv_paid, inv_topup (an account credit top-up), inv_credit and inv_credited (voided by a credit note) are 0 or 1. inv_source_total / inv_source_currency are set when the invoice was converted from another currency. inv_bp_status, inv_bp_invoice_id and inv_bp_invoice_url describe a pending cryptocurrency payment. Unpaid invoices also list the servers they cover in services.
orders - your orders with their products. order_billing_type is hourly for pay-as-you-go orders; order_billing_cycle is the number of months per period for recurring orders.
billing - your current payment method. payment_type is the method in use, for example invoice (manual bank transfer), credit (prepaid account credit), paypal or the card type. payment_automated is 1 when invoices are charged automatically. support_invoice, support_vipps and support_alipay tell which optional payment options your account can use.
card_details - saved cards (only the last 4 digits are returned).
credit - your prepaid account credit per currency.
hourly_credit - accrued pay-as-you-go usage measured against your credit. When applies is false nothing hourly is running and the rest can be ignored. percent is usage as a share of the allowance, stage is 0 (fine), 1 (above warn1 percent), 2 (above warn2 percent) or 3 (exhausted), and suspended is true when hourly services are suspended because the credit is used up.
hourly - your running pay-as-you-go services (servers and additional IPs) with the hourly rate, the monthly cap, hours used this month and the estimated cost so far.
exchange_rates - the currencies we bill in.
card_client_secret_card / card_client_secret_paypal - one-time values used by the control panel to add a card or PayPal account in the browser. Not needed for API integrations.
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":{
"exchange_rates":[
{ "id":"1", "currency_code":"NOK", "prefix":"", "suffix":" kr", "exchange_rate":"1" }
],
"invoices":[
{
"inv_id":"88120",
"inv_md5":"0cc175b9c0f1b6a831c399e269772661",
"order_id":"55012",
"inv_number":"40211",
"inv_kid":"0402110",
"inv_date":"1759276800",
"inv_duedate":"1760140800",
"inv_bookdate":"0",
"inv_postponed":"0",
"inv_total":"199.00",
"inv_source_total":"0",
"inv_source_currency":"",
"inv_vat":"25",
"inv_paid":"0",
"inv_bp_status":"",
"inv_bp_invoice_id":"",
"inv_bp_invoice_url":"",
"inv_currency":"NOK",
"inv_topup":"0",
"inv_credit":"0",
"inv_credited":"0",
"inv_total_vat":248.75,
"services":[
{ "srv_id":"3523", "srv_name":"web01", "srv_deleted":"0" }
]
}
],
"orders":[
{
"order_id":"55012",
"order_number":"55012",
"order_date":"1727740800",
"order_contract_to":"0",
"order_billing_type":"recurring",
"order_billing_date":"1759276800",
"order_total":"199.00",
"order_billing_cycle":"1",
"order_status":"active",
"order_currency":"NOK",
"products":[
{
"op_id":"120331",
"srv_id":"3523",
"product_id":"812",
"op_type":"server",
"product_alt_name":"",
"op_sum":"1",
"product_name":"VPS M",
"srv_name":"web01"
}
]
}
],
"billing":{
"payment_id":"8",
"payment_type":"credit",
"payment_label":"Account credit",
"payment_automated":"1",
"support_invoice":true,
"support_vipps":false,
"support_alipay":false
},
"card_details":[
{
"card_id":"301",
"card_last4":"4242",
"card_expiry_month":"12",
"card_expiry_year":"2028",
"card_brand":"visa",
"card_funding":"credit",
"card_3ds":true,
"card_default":"1"
}
],
"credit":[
{ "credit_currency":"NOK", "credit_amount":"500.00" }
],
"hourly_credit":{
"applies":true,
"usage":120.5,
"allowance":500,
"remaining":379.5,
"percent":24.1,
"stage":0,
"currency":"NOK",
"suspended":false,
"warn1":80,
"warn2":95
},
"hourly":[
{
"order_id":55130,
"op_id":120400,
"type":"server",
"srv_id":3600,
"hdd_id":0,
"srv_name":"build01",
"rate_hourly":0.32,
"monthly_cap":199,
"accrued_hours":96,
"estimated_month_cost":30.72,
"backups":0,
"currency":"NOK"
}
],
"card_client_secret_card":"...",
"card_client_secret_paypal":"..."
}
}
Required parameters
inv_md5 (string - inurl - the invoice's inv_md5 from GET /billing, 32 hexadecimal characters)
Decode data from base64 and save it as filename. Returns 404 if the invoice is not found.
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":{
"filename":"F40211.pdf",
"data":"JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoK..."
}
}
Only top-up invoices (inv_topup 1) that are not paid can be removed. The invoice is credited and no longer shows as unpaid.
Required parameters
inv_md5 (string - inurl - the invoice's inv_md5 from GET /billing)
Returns status 200 with no data on success.
// 403 - "Only top-up invoices can be removed."
// 403 - "Paid top-up invoices cannot be removed."
// 404 - "Invoice not found."
// 409 - "Invoice has already been credited."
Without payment_id the invoice is paid with your current payment method: a saved card, a saved PayPal account or account credit is charged right away. With manual bank transfer as the payment method, use the bank details and KID on the invoice instead.
With payment_id you can pay this one invoice another way without changing your payment method. Methods that need you to complete the payment on an external page return the page in url or bp_invoice_url; open it in a browser. The invoice is marked paid once the payment is confirmed.
Required parameters
inv_id (numeric - body - the invoice's inv_id from GET /billing)
Optional parameters
payment_id (numeric - body) - 8 = account credit, 5 = cryptocurrency (returns bp_invoice_id and bp_invoice_url), 11 = Vipps (private Norwegian residents, NOK invoices only, returns url), 6 = Alipay (returns url)
Example request body
{
"inv_id":88120,
"payment_id":8
}
Example return data (paid immediately)
{
"meta":{
"status":200,
"status_message":"200 OK",
"message":"Invoice has been paid successfully."
}
}
Example return data (payment page)
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":{
"url":"https://..."
}
}
Error responses
// 404 - "Invoice was not found." / "Unable to locate invoice." (unknown, not yours or already paid)
// 400 - "Unable to charge account credit. Insufficient funds."
// 400 - "Unable to charge card."
// 400 - "Vipps only supports NOK payments." / "Vipps is only available to private Norwegian residents."
// 400 - "Crypto payments has been disabled for this account."
Cards and PayPal accounts are added from the control panel, since they must be confirmed in a browser. Through the API you can switch between the methods below. Switching to any method other than card or PayPal removes all saved cards.
Required parameters
payment_type (string - body) - invoice (manual bank transfer; Norwegian customers only, and not while pay-as-you-go servers are running) or credit (prepaid account credit)
Example request body
{
"payment_type":"credit"
}
Returns status 201. payment_automated is 1 when invoices will be charged automatically with the new method.
{
"meta":{ "status":201, "status_message":"201 Created" },
"data":{
"payment_automated":1
}
}
Error responses
// 404 - unknown payment_type
// 400 - "Manual bank-transfer billing is not available for your account. Contact support."
// 400 - "You have active pay-as-you-go (hourly) servers. Keep a card on file or prepaid balance, or terminate those servers, before switching to manual bank transfer."
Required parameters
card_id (numeric - inurl - card_id from card_details in GET /billing)
default (numeric - body - must be 1)
Example request body
{
"default":1
}
Returns status 200 with no data on success.
// 403 - "Card ID is invalid and not found."
// 403 - "Request incomplete." (default missing or not 1)
Your last remaining card cannot be removed. After removal, the remaining card becomes the default.
Required parameters
card_id (numeric - inurl - card_id from card_details in GET /billing)
Returns status 200 with no data on success.
// 403 - "Card ID is invalid and not found."
// 403 - "Cannot remove primary card."
// 403 - "Unable to remove card, unable to contact payment processor."
A summary of your account for overview pages. Available to every valid token and API key, regardless of its permissions.
Parameters
{none}
announcements are the 4 latest news posts and status_messages the 5 latest issues from our status page. services counts your dedicated and virtual servers, DNS zones and registered domains. billing.outstanding_amount is the unpaid amount including VAT per currency, billing.unpaid the number of unpaid invoices and billing.overdue how many of them are past due. unpaid_orders counts new orders awaiting payment and orders_in_review orders awaiting manual review. incomplete_profile is true when your address is missing. For API keys and users without billing access, the billing figures, unpaid_orders, orders_in_review and hourly_credit are returned empty. hourly_credit has the same format as in GET /billing.
Example return data
{
"meta":{ "status":200, "status_message":"200 OK" },
"data":{
"announcements":[
{
"news_id":"52",
"news_title":"New datacenter region",
"news_text":"...",
"news_timestamp":"1759276800"
}
],
"status_messages":[
{
"title":"Scheduled network maintenance",
"link":"https://gigahoststatus.com/issue/abc123",
"date":1759300000
}
],
"flags":{
"cust_beta_dns":0
},
"services":{
"dedicated":1,
"virtual":3,
"dns_zones":12,
"registered_domains":8
},
"incomplete_profile":false,
"billing":{
"outstanding_amount":{ "NOK":248.75 },
"unpaid":1,
"overdue":0
},
"unpaid_orders":0,
"orders_in_review":0,
"hourly_credit":{
"applies":false,
"usage":0,
"allowance":0,
"remaining":0,
"percent":0,
"stage":0,
"currency":"NOK",
"suspended":false,
"warn1":80,
"warn2":95
}
}
}
Order and deploy new cloud servers and dedicated servers. A typical flow is: read the catalog with GET /deploy/servers, pick an operating system (GET /reinstall/distro), a one-click app (GET /reinstall/apps) or one of your ISOs (GET /deploy/isos), place the order with POST /deploy/servers, then poll GET /deploy/status with the returned order_ids until all_ready is true.
POST and DELETE requests take a JSON body. Personal API keys need the deploy permission: read access for the GET endpoints, read/write access for POST and DELETE. Prices are in NOK and exclude VAT.
Lists everything that can be deployed through POST /deploy/servers, grouped into tiers. Each product has a type: vm (cloud server), dedicated (dedicated server) or auction (a specific used dedicated server from the server auction, listed in its own tier; deploy it with its auction_id). A tier is in_stock when at least one of its products is in stock or built to order; tier quantity is the summed stock of those products.
Product fields:
in_stock - can be deployed right now
quantity - units in stock for dedicated servers (always 0 for cloud servers)
built_to_order - sold out, but can still be ordered and will be set up for you (dedicated only)
waitlist_eligible - sold out in every datacenter and can be reserved or signed up for a notification with the waitlist parameter
allow_hourly / allow_recurring - which billing_period values the product accepts
discount_year - percent discount on the annual term (0 = none)
setup - one-time setup fee on recurring terms
contract - minimum contract length in months (0 = none)
monthly_extra - extra fee per month added when billed on the monthly term
addons - display specs for dedicated and auction servers as name/value pairs (the names are Norwegian labels)
config_addons - selectable configuration options (see opts on POST /deploy/servers); the option with is_default true is included in the price, other options add rate_monthly and opt_setup
vm_cores, vm_memory (GB), vm_storage (GB), vm_bw, vm_bw_type - cloud server specs (empty for dedicated and auction)
specs - machine-readable specs with the same shape for every product type. Dedicated and auction servers also include gpus. For dedicated servers bw is in GB when bw_type is "quota"
price_id - pass this as price_id when deploying (0 for auctions)
rate_hourly / rate_monthly - hourly rate and monthly price (hourly billing never exceeds rate_monthly in a month)
region_ids - regions the product can be deployed in
dc_ids / dc_stock - datacenters the product can be placed in, and whether each one has stock of its own
regions and datacenters only contain locations where at least one listed product can be deployed. The eligibility object describes your account's payment standing, so you can tell up front whether an hourly deploy will be accepted: hourly servers are allowed when qualifies_arrears is true, or when credit_nok covers one month of all your hourly services. hourly_applies, hourly_usage, hourly_allowance and hourly_percent show how much of your account credit your hourly services have used this month; at 100 percent new hourly deploys are refused until you top up.
Parameters
{none}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"tiers":[
{
"group_id":1,
"group_name":"Cloud Servers",
"in_stock":true,
"quantity":0,
"products":[
{
"product_id":101,
"product_hash":"a1b2c3d4",
"product_name":"Cloud 2",
"type":"vm",
"in_stock":true,
"quantity":0,
"built_to_order":false,
"waitlist_eligible":false,
"allow_hourly":true,
"allow_recurring":true,
"discount_year":15,
"setup":0,
"contract":0,
"monthly_extra":0,
"addons":[],
"config_addons":[],
"auction_id":0,
"vm_cores":"2",
"vm_memory":"4",
"vm_storage":"80",
"vm_bw":"5",
"vm_bw_type":"TB",
"specs":{
"cpu_cores":2,
"cpu_sockets":1,
"cpu_model":null,
"ram_gb":4,
"disks":[
{
"size_gb":80,
"type":"NVMe"
}
],
"bw":5,
"bw_type":"TB",
"uplink_gbps":null
},
"price_id":555,
"rate_hourly":0.14375,
"rate_monthly":90,
"region_ids":[1],
"dc_ids":[1,2],
"dc_stock":{
"1":true,
"2":false
}
}
]
},
{
"group_id":4,
"group_name":"Dedicated Servers",
"in_stock":true,
"quantity":3,
"products":[
{
"product_id":120,
"product_hash":"e5f6a7b8",
"product_name":"Dedicated E-64",
"type":"dedicated",
"in_stock":true,
"quantity":3,
"built_to_order":false,
"waitlist_eligible":false,
"allow_hourly":true,
"allow_recurring":true,
"discount_year":10,
"setup":0,
"contract":0,
"monthly_extra":0,
"addons":[
{
"name":"Processor",
"value":"AMD EPYC 4344P"
},
{
"name":"Memory",
"value":"64 GB"
}
],
"config_addons":[
{
"addon_id":310,
"addon_name":"Port",
"addon_type":"radio",
"options":[
{
"opt_id":901,
"opt_value":"1 Gbit/s",
"opt_setup":0,
"price_id":0,
"rate_monthly":0,
"is_default":true
},
{
"opt_id":902,
"opt_value":"10 Gbit/s",
"opt_setup":0,
"price_id":77,
"rate_monthly":500,
"is_default":false
}
]
}
],
"auction_id":0,
"vm_cores":"",
"vm_memory":"",
"vm_storage":"",
"vm_bw":"",
"vm_bw_type":"",
"specs":{
"cpu_cores":8,
"cpu_sockets":1,
"cpu_model":"AMD EPYC 4344P",
"ram_gb":64,
"disks":[
{
"size_gb":960,
"type":"NVMe"
},
{
"size_gb":960,
"type":"NVMe"
}
],
"gpus":[],
"bw":10000,
"bw_type":"quota",
"uplink_gbps":1
},
"price_id":560,
"rate_hourly":1.27778,
"rate_monthly":800,
"region_ids":[1],
"dc_ids":[1],
"dc_stock":{
"1":true
}
}
]
}
],
"regions":[
{
"region_id":"1",
"region_name":"Norway",
"region_name_short":"NO",
"region_country":"NO",
"region_icon":"no",
"region_active":"1"
}
],
"datacenters":[
{
"dc_id":1,
"dc_name":"DC1",
"region_id":1,
"region_name":"Norway",
"region_name_short":"NO",
"region_location":"Sandefjord",
"region_country":"NO",
"region_icon":"no"
}
],
"currency":"NOK",
"eligibility":{
"verified":1,
"has_method":true,
"method_qualifies":true,
"has_paid_invoice":true,
"qualifies_arrears":true,
"credit_nok":0,
"hourly_applies":false,
"hourly_usage":0,
"hourly_allowance":0,
"hourly_percent":0,
"hourly_currency":"NOK"
}
}
}
Only checks the code, it does not use it up. Pass the code as coupon_code when deploying. type is "percent" (value is a percentage off the monthly price) or "static" (value is a fixed amount in NOK off the monthly price). reusable is 1 for codes that can be used more than once and 0 for single-use codes, which are used up when an order is placed with them. Discount codes only apply to recurring terms (monthly, quarterly, annual) and a single server.
Required parameters
code (string - query - the discount code)
pid (numeric - query - product ID from the catalog)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"coupon_id":42,
"code":"SPRING25",
"type":"percent",
"value":25,
"reusable":1
}
}
Error responses
// Missing code or pid
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Required field is invalid: code"
}
}
// Unknown, expired or not valid for this product
{
"meta":{
"status":404,
"status_message":"404 Not Found",
"message":"Discount code is invalid or has expired."
}
}
Poll this with the order_ids from POST /deploy/servers while servers are being provisioned. Works for both hourly and recurring orders. Orders that are not yours are ignored, and orders that have been cancelled or whose server has been deleted are left out of the list.
Status values:
waitlist - reserved on the waitlist, deploys automatically once capacity frees up
waiting - order received, waiting to be processed (for example review or payment)
deploying - the server is being set up
installing - the operating system is being installed
ready - the server is installed and running
rescue - the server is booted into rescue mode
iso - the server is booted from your ISO
all_ready is true when every listed server is ready, rescue or iso, and false when the list is empty. ip and ipv6 are filled in as soon as addresses are assigned, which is before the install finishes. hostname is the requested hostname, or srv{srv_id}.gigahost.no when none was given. The root password is only returned while a server is installing and no SSH key was supplied, or while it is in rescue mode; otherwise password is an empty string. Store it right away, it is not available after the install.
install_progress is an object while status is installing, otherwise null:
step - waiting, boot, loader, starting, disks, os, packages, configure, post or failed
progress - estimated percent complete, 0 to 100
done / total - packages installed of total when the installer reports a count, otherwise null
date_started - when the install started (unix timestamp)
step_started - when the current step started (unix timestamp)
stalled - true when the install has not moved for a long time
failed - true when the install has failed (step is failed and progress is 100)
app is an object while a one-click app is being installed on the server, otherwise null. It holds name, url, admin_user and admin_password. The app is installed on the first boot after the operating system, so it can still be installing after status has become ready. The admin password is only returned here while the app installs; save it then. Use GET /servers/{id}/app for the app's status after that.
Required parameters
ids (string - query - comma-separated list of order IDs, e.g. ?ids=10001,10002)
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"servers":[
{
"order_id":10001,
"order_number":"55001",
"hostname":"web1.example.no",
"srv_id":3500,
"ip":"185.181.60.10",
"ipv6":"2a03:94e0:ffff::10",
"status":"installing",
"password":"",
"app":{
"name":"WordPress",
"url":"https://web1.example.no",
"admin_user":"admin",
"admin_password":"xxxxxxxxxxxx"
},
"install_progress":{
"step":"packages",
"progress":72,
"done":410,
"total":620,
"date_started":1750000000,
"step_started":1750000400,
"stalled":false,
"failed":false
}
},
{
"order_id":10002,
"order_number":"55002",
"hostname":"web2.example.no",
"srv_id":3501,
"ip":"185.181.60.11",
"ipv6":"2a03:94e0:ffff::11",
"status":"ready",
"password":"",
"app":null,
"install_progress":null
}
],
"all_ready":false
}
}
Only completed ISO uploads belonging to your account are returned, sorted by name. Use an iso_id from this list when deploying a cloud server from your own installation image. ISO installs are not available for dedicated servers.
Parameters
{none}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"isos":[
{
"iso_id":"42",
"iso_name":"debian-12.iso",
"iso_size":"650000000"
}
]
}
}
Reservations are held orders that deploy automatically when capacity frees up anywhere in the region, so they have no server yet. Nothing is billed while a reservation waits. billing_type is "hourly" or "recurring"; total is the monthly cap for hourly orders and the monthly price for recurring orders. Notify-only signups record interest in a sold-out product and trigger an email when it is back in stock; signups that have already been emailed are not listed. Use the order_id of a reservation or the notify_id of a signup to cancel it. Timestamps are unix timestamps.
Parameters
{none}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"reservations":[
{
"order_id":10050,
"order_number":"55050",
"product_name":"Cloud 2 (NO)",
"region_id":1,
"region_name":"Norway",
"billing_type":"hourly",
"total":90,
"currency":"NOK",
"reserved_at":1750000000
}
],
"notifications":[
{
"notify_id":7,
"product_id":120,
"product_name":"Dedicated E-64",
"region_id":1,
"region_name":"Norway",
"signed_up_at":1750000000
}
]
}
}
Pass order_id (to cancel a held reservation) or notify_id (to remove a notify signup), in the JSON body or as query parameters. If both are given, only order_id is used. Both are scoped to your account. A reservation can only be cancelled while it is still waiting; once it has been deployed it is a normal order and is no longer cancellable here.
Required parameters
One of: order_id (numeric - body or query - reservation order ID) or notify_id (numeric - body or query - notify signup ID)
Example request body
{
"order_id":10050
}
Example return data
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"success":true,
"message":"Reservation cancelled."
}
}
// For a notify signup the message is "Notification removed."
Error responses
// Neither id supplied
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Provide order_id or notify_id."
}
}
// Reservation already deployed or not found
{
"meta":{
"status":404,
"status_message":"404 Not Found",
"message":"Reservation was not found or is no longer cancellable."
}
}
// Notify signup not found
{
"meta":{
"status":404,
"status_message":"404 Not Found",
"message":"Notification signup was not found."
}
}
Queues one or more servers for provisioning. One order is created per server; poll GET /deploy/status with the returned order_ids. Products, price IDs, regions and datacenters come from GET /deploy/servers.
Image. Choose exactly one: an operating system or one-click app (os_id), one of your ISOs (iso_id, cloud servers only), or rescue mode (rescue: 1). rescue takes precedence over iso_id, and iso_id over os_id. Operating system IDs come from GET /reinstall/distro and GET /reinstall/distro/{id}.
One-click apps. To deploy an app instead of a plain operating system, pass the app's os_id from GET /reinstall/apps as os_id. The server is installed with the app's operating system and the app is set up on its first boot. Apps can be deployed on cloud servers and dedicated servers, but not on container-based cloud products; apps with os_dedicated_only set to 1 need a dedicated server, and os_minram / os_min_disk give the minimum memory and disk in GB. os_app_domain tells whether the app takes a domain: 0 = no, 1 = optional, 2 = recommended. Optionally pass app_domain (the app is served on it with a trusted certificate if its DNS already points to the server's IP; otherwise the app is set up on the IP address and the domain can be added later) and app_email (used for the certificate and, for apps that log in by email, as the admin login). app_domain can only be used when deploying a single server. Both are ignored when os_id is not an app. The app login is shown in GET /deploy/status while the app installs.
Region or datacenter. Pass region_id to let us place the server in any datacenter in that region, or dc_id to pin it to one datacenter (region_id is then taken from the datacenter and can be left out). The datacenter must be one of the product's dc_ids. If the chosen datacenter is sold out while others still have capacity, the request fails instead of going to the waitlist. For a dedicated server that is built to order, dc_id is ignored and the server is placed within the region.
Billing. billing_period "hourly" (default) is pay-as-you-go: the server is billed per hour at rate_hourly, never more than monthly_cap per month. It requires a verified account, or a non-prepaid card or PayPal on file plus at least one paid invoice (a 100 NOK top-up paid with the card is enough), or a prepaid balance covering one month of all your hourly services including this one. Hourly deploys are also refused when your hourly services have already used all the credit on your account this month. The recurring terms "monthly", "quarterly" and "annual" create an invoice per server, with any setup fee, the product's monthly_extra on the monthly term and the product's annual discount on the annual term; VAT is added for Norwegian customers. Verified accounts are invoiced, other accounts with a card or PayPal are charged right away, and accounts paying by invoice deploy once the invoice is paid. New accounts may have the order held for a manual review before it deploys. Selecting any non-default option in opts makes the order a custom configuration, which is only available on recurring terms.
Discount codes. coupon_code applies to recurring terms only and to a single server (quantity 1). It is ignored for hourly and waitlist orders. The discount comes off the monthly price before any annual discount and stays on renewals. Single-use codes are used up when the order is placed. Validate a code first with GET /deploy/coupon.
Waitlist. For a product that is sold out in every datacenter (waitlist_eligible in the catalog), set waitlist. "reserve" holds the order and deploys it automatically when capacity frees up anywhere in the region; nothing is billed while it waits and dc_id is ignored. "notify" creates no order and just emails you when the product is back in stock. If the product is in stock when the request arrives, the deploy proceeds normally and waitlist is ignored. Server auctions cannot be reserved. See GET /deploy/waitlist to list and cancel reservations.
Required parameters
pid (numeric - body - product ID; or use hash)
hash (string - body - product hash; alternative to pid)
price_id (numeric - body - price_id of the product from the catalog; any number, e.g. 0, for an auction)
region_id (numeric - body - region to deploy in; not needed when dc_id is given)
One of: os_id, iso_id or rescue
Optional parameters
dc_id (numeric - body - datacenter to deploy in, from the catalog's datacenters)
os_id (numeric - body - operating system or one-click app to install)
iso_id (numeric - body - your uploaded ISO to boot from, cloud servers only)
rescue (numeric - body - 1 to boot into rescue mode)
app_domain (string - body - domain for a one-click app, single server only)
app_email (string - body - email address for a one-click app)
firstboot (string - body - script run once on the installed system at first boot, max 32768 bytes)
billing_period (string - body - "hourly" (default), "monthly", "quarterly" or "annual")
coupon_code (string - body - discount code, recurring terms and a single server only)
waitlist (string - body - "reserve" or "notify" for a sold-out product)
quantity (numeric - body - number of servers to deploy, default 1)
hostnames (array of strings - body - requested hostname per server, in order; empty entries get the default hostname)
ssh_keys (array of numeric - body - IDs of your SSH keys to authorize, from GET /account; keys that are not yours are ignored)
backups (numeric - body - 1 to enable backups, adds 25% to the price; cloud servers only, ignored for dedicated)
auction_id (numeric - body - deploy a specific server auction; the product is taken from the auction and quantity is forced to 1)
opts (object - body - selected configuration options as {"addon_id":"opt_id-price_id"}, using config_addons from the catalog)
Example request body
{
"pid":101,
"price_id":555,
"region_id":1,
"os_id":12,
"quantity":2,
"backups":1,
"hostnames":["web1.example.no","web2.example.no"],
"ssh_keys":[7,8]
}
Example request body (one-click app in a chosen datacenter, annual term with a discount code)
{
"pid":120,
"price_id":560,
"dc_id":1,
"os_id":240,
"app_domain":"blog.example.no",
"app_email":"[email protected]",
"billing_period":"annual",
"coupon_code":"SPRING25",
"hostnames":["blog.example.no"],
"ssh_keys":[7],
"opts":{
"310":"902-77"
}
}
Example return data (hourly)
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"success":true,
"message":"Servers queued for deployment.",
"order_ids":[10001,10002],
"order_numbers":[55001,55002],
"quantity":2,
"rate_hourly":0.14375,
"monthly_cap":90,
"currency":"NOK"
}
}
Example return data (recurring term)
monthly is the price per month after any discount code and annual discount, including options and excluding VAT. discount is the annual discount in percent and vat the VAT percent applied. pending_payment is true while the server waits for payment or review, and under_review is true when the order is held for a manual review. The message is then "Your order has been received. Your server deploys once the invoice is paid." or "Your order has been received and is being reviewed. Your server deploys once it is approved."
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"success":true,
"message":"Servers queued for deployment.",
"order_ids":[10003],
"order_numbers":[55003],
"quantity":1,
"billing_period":"annual",
"term":12,
"monthly":990,
"setup":0,
"discount":10,
"vat":25,
"currency":"NOK",
"pending_payment":false,
"under_review":false
}
}
Example return data (waitlist reserve)
For a recurring reservation, rate_hourly and monthly_cap are replaced by billing_period.
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"success":true,
"mode":"reserve",
"waitlisted":true,
"message":"Reserved. Your server deploys automatically when capacity becomes available.",
"order_ids":[10050],
"order_numbers":[55050],
"quantity":1,
"rate_hourly":0.14375,
"monthly_cap":90,
"currency":"NOK"
}
}
Example return data (waitlist notify)
{
"meta":{
"status":200,
"status_message":"200 OK"
},
"data":{
"success":true,
"mode":"notify",
"message":"We'll email you when this product is available again."
}
}
Error responses
// Missing or invalid field (also pid, price_id, dc_id, app_domain, app_email)
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Required field is invalid: region_id"
}
}
// No image option selected
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Choose an operating system, an ISO, or rescue mode."
}
}
// Profile incomplete
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Please complete your account profile before ordering."
}
}
// An earlier order is still awaiting review
{
"meta":{
"status":403,
"status_message":"403 Forbidden",
"message":"You already have an order awaiting review. Please wait until it has been processed before placing a new order."
}
}
// Out of stock (cloud servers: "Product is out of stock.")
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Not enough stock to deploy 2 server(s)."
}
}
// Chosen datacenter sold out while other datacenters have capacity
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Product is out of stock in the selected datacenter."
}
}
// Product not offered in the chosen datacenter
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Product is not available in the selected datacenter."
}
}
// Product cannot be ordered hourly (or "on a recurring term.")
{
"meta":{
"status":403,
"status_message":"403 Forbidden",
"message":"This product cannot be ordered hourly."
}
}
// Non-default options selected on an hourly order
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Custom configurations are not available hourly. Choose a monthly, quarterly or annual term."
}
}
// ISO chosen for a dedicated server
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"ISO installs are not available for dedicated servers."
}
}
// App not available on this product (also "This app is only available on dedicated servers."
// and "This app is not available right now.")
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Apps can only be installed on KVM servers and dedicated servers."
}
}
// app_domain given with quantity above 1
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"One domain cannot be used for several servers. Order them one at a time, or leave the domain empty."
}
}
// Discount code rejected (also "Discount codes can only be used when deploying a single server.")
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Discount code is invalid or has expired.",
"reason":"coupon"
}
}
// Hourly not allowed without a qualifying payment method or prepaid balance
{
"meta":{
"status":403,
"status_message":"403 Forbidden",
"message":"Hourly servers require a non-prepaid card or PayPal on file plus at least one paid invoice on your account (a minimum 100 NOK top-up paid with your card is enough), or a prepaid balance of at least 180.00 NOK covering one month of all your active hourly services. Prepaid and virtual cards do not qualify on their own.",
"reason":"payment",
"required":180,
"balance":0,
"currency":"NOK"
}
}
// Hourly services have used all account credit this month
{
"meta":{
"status":403,
"status_message":"403 Forbidden",
"message":"Your hourly services have used 500.00 NOK this month, which is all of the 500.00 NOK credit on your account. Top up your account to deploy more hourly services.",
"reason":"hourly_credit",
"usage":500,
"allowance":500,
"percent":100,
"currency":"NOK"
}
}
// Recurring card charge declined (orders and invoices are kept and payment is retried)
{
"meta":{
"status":402,
"status_message":"402 Payment Required",
"message":"Your card was declined. The order is saved and we will retry payment; your server deploys once it is paid.",
"reason":"payment_declined",
"order_ids":[10003],
"order_numbers":[55003]
}
}
// Auction no longer available
{
"meta":{
"status":404,
"status_message":"404 Not Found",
"message":"Auction was not found or is no longer available."
}
}
// Server auction cannot be reserved
{
"meta":{
"status":400,
"status_message":"400 Bad Request",
"message":"Auctions cannot be reserved."
}
}
Manage web hosting accounts and everything inside them: domains, email, databases, FTP, cron jobs, files, DNS, subdomains, PHP versions, SSL, one-click applications and backups.
Every account is identified by its {id} (the hosting account id from GET /webhosting). You can only access accounts that belong to you. Read operations need a token or API key with read access to webhosting; everything that creates, changes or deletes needs read-write access.
Several domains per account. A hosting account can host more than one domain. One of them is the primary domain; the others are added with POST /webhosting/{id}/domains. Each domain has its own website folder, email accounts, forwarders, autoresponders, catch-all, DKIM, spam filter, FTP accounts, subdomains, DNS records, PHP version and SSL certificate. Endpoints that work on one domain accept the optional query parameter ?domain=example.com (for example GET /webhosting/1234/emails?domain=example.com). Without it, the primary domain is used. The domain can be given in Unicode or punycode form. If the domain is not on the account, the request fails with status 404 ("Domain not found on this hosting account."). Most other endpoints under /webhosting/{id}/... also check the parameter, even those that do not depend on the domain, so only send domain where it is relevant. The endpoints that use it say so below.
Suspended accounts. While an account is suspended, all endpoints under /webhosting/{id}/... return status 403 ("Hosting account is suspended. Contact support."). GET /webhosting/{id} and DELETE /webhosting/{id}/cancel still work.
The domain field is the primary domain of each account. Deleted accounts are not included.
Example return data
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": {
"hosting": [
{
"hosting_id": 1234,
"zone_id": 5678,
"domain": "example.no",
"username": "exampleno",
"email": "[email protected]",
"package": "Webhosting M",
"status": "active",
"suspended": 0,
"created_date": "2026-01-15",
"order_number": 55012,
"order_renewal": "2026-07-15",
"order_status": "active"
}
]
}
}
Parameters
id (numeric, in URL) - hosting account id
The response has the same fields as the list, plus:
domains (array) - every domain on the account, primary first. Each entry has domain, zone_id (0 if the DNS zone no longer exists on your account) and primary (boolean)
stats (object) - current usage, the same data as GET /webhosting/{id}/stats
package_info (object) - the package limits. Each limit is an object with value and unlimited (boolean). ssh (boolean) tells whether the package includes SSH
ssh_password (string) - the SSH/SFTP password. Only included when the package includes SSH
server_ip, server_ipv6 (string) - the addresses of the server the account is on
This endpoint also works while the account is suspended.
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": {
"hosting_id": 1234,
"domain": "example.no",
"username": "exampleno",
"package": "Webhosting M",
"status": "active",
"suspended": 0,
"order_number": 55012,
"order_renewal": "2026-07-15",
"order_status": "active",
"server_ip": "203.0.113.10",
"server_ipv6": "2001:db8::10",
"domains": [
{ "domain": "example.no", "zone_id": 5678, "primary": true },
{ "domain": "example.com", "zone_id": 5679, "primary": false }
],
"stats": { "bandwidth": "1520.4", "quota": "830.2", "nemails": "4", "...": "..." },
"package_info": {
"name": "Webhosting M",
"quota": { "value": 20000, "unlimited": false },
"domains": { "value": 5, "unlimited": false },
"email_accounts": { "value": 0, "unlimited": true },
"ssh": true,
"...": "..."
},
"ssh_password": "s3cretPassw0rd"
}
}
Required parameters
zone_id (numeric) - the domain to host (a DNS zone on your account). This becomes the primary domain
product_id (numeric) - the hosting package to order
billing_period (numeric) - number of months: 1, 3, 6 or 12
Optional parameters
update_dns (numeric) - set to 1 to create the standard web and mail DNS records for the domain (A/AAAA for the domain, www, ftp, mail and smtp, an MX record, SPF and DMARC). Existing records with the same names and types are replaced, including all TXT records on the domain itself. Only works when the domain uses our DNS
On success the account is created, an order and invoice are created for the first period and a confirmation email is sent. Returns status 201. Returns 409 if the domain is already on a hosting account, and 403 if your account is not allowed to place orders.
{
"meta": { "status": 201, "status_message": "201 Created" },
"data": {
"message": "Webhosting account created successfully.",
"hosting_id": 1234,
"domain": "example.no",
"username": "exampleno"
}
}
Required parameters
id (numeric, in URL) - hosting account id
product_id (numeric) - the package to move to
The new price applies from the next renewal. If the new package costs more and there are at least 35 days left of the current billing period, an extra invoice is created and sent for the price difference for the whole months that are left. Returns status 201.
{
"meta": { "status": 201, "status_message": "201 Created" },
"data": {
"message": "Webhosting account upgraded successfully.",
"hosting_id": 1234,
"domain": "example.no",
"username": "exampleno"
}
}
Required parameters
id (numeric, in URL) - hosting account id
password (string) - the new password, at least 8 characters
Only available when the hosting package includes SSH; otherwise status 403 is returned. The current password is shown as ssh_password in GET /webhosting/{id}. Email, FTP and database accounts have their own passwords and are not affected.
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": { "message": "Password changed successfully" }
}
Required parameters
id (numeric, in URL) - hosting account id
reason (string) - why the account is being cancelled. The characters < > " ' & are not allowed
Optional parameters
early_termination (boolean) - set to true to terminate and delete the data immediately with no refund. When false (default) the account is scheduled to end on the next billing date and any unpaid, not-yet-due invoice is credited.
Returns status 400 if the account has already been cancelled.
Parameters
id (numeric, in URL) - hosting account id
The usage covers all domains on the account. Fields include bandwidth and quota (disk use) in MB, and counters such as vdomains (domains), nsubdomains, nemails, nemailf (forwarders), nemailr (autoresponders), ftp and mysql (databases).
Parameters
id (numeric, in URL) - hosting account id
Redis is enabled automatically on new accounts. enabled is "1" when it is running. Connect through the socket /home/{username}/.redis/redis.sock.
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": { "enabled": "1" }
}
Add more domains to an account, choose the primary domain and set the PHP version per domain. The list of domains with the primary flag is returned in GET /webhosting/{id} (the domains field).
Parameters
id (numeric, in URL) - hosting account id
A flat list of hostnames: each domain followed by its subdomains. To see which domain is the primary one, use the domains field of GET /webhosting/{id}.
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": {
"domains": [ "example.no", "blog.example.no", "example.com" ]
}
}
The domain gets its own website folder, email and SSL on the account at no extra cost. The number of domains is limited by the package.
Required parameters
id (numeric, in URL) - hosting account id
zone_id (numeric) - the domain to add (a DNS zone on your account)
Optional parameters
update_dns (numeric) - set to 1 to create the standard web and mail DNS records for the domain (A/AAAA for the domain, www, ftp, mail and smtp, an MX record, SPF, DMARC and DKIM if enabled). Existing records with the same names and types are replaced, including all TXT records on the domain itself. Only works when the domain uses our DNS
Returns status 201. Returns 404 if the DNS zone is not on your account and 409 if the domain is already on a hosting account. records lists the DNS records the domain needs. When dns_updated is false, add them yourself at your DNS provider.
{
"meta": { "status": 201, "status_message": "201 Created" },
"data": {
"message": "Domain added successfully",
"domain": "example.com",
"zone_id": 5679,
"dns_updated": false,
"records": [
{ "name": "example.com", "type": "A", "value": "203.0.113.10", "ttl": 3600, "priority": null },
{ "name": "www.example.com", "type": "A", "value": "203.0.113.10", "ttl": 3600, "priority": null },
{ "name": "example.com", "type": "MX", "value": "mail.example.com.", "ttl": 3600, "priority": 10 },
{ "name": "example.com", "type": "TXT", "value": "v=spf1 a mx ip4:203.0.113.10 ~all", "ttl": 3600, "priority": null },
{ "name": "_dmarc.example.com", "type": "TXT", "value": "v=DMARC1;p=none;", "ttl": 3600, "priority": null }
]
}
}
Required parameters
id (numeric, in URL) - hosting account id
domain (string, in URL) - a domain already on the account
The account is then listed under this domain, the account's default website folder (public_html) points to it, and endpoints called without ?domain= use it. Returns 400 if the domain is already the primary domain and 404 if it is not on the account.
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": { "message": "Primary domain changed successfully", "domain": "example.com" }
}
Required parameters
id (numeric, in URL) - hosting account id
domain (string, in URL) - the domain to remove
The website files, mailboxes and subdomains of the domain are deleted. This cannot be undone. The DNS zone is kept. The primary domain cannot be removed (status 400); make another domain primary first.
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": { "message": "Domain removed successfully", "domain": "example.com" }
}
Parameters
id (numeric, in URL) - hosting account id
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
versions is sorted newest first. current can be null, and versions can be empty if the version cannot be changed for the domain.
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": {
"php": { "current": "8.3", "versions": [ "8.4", "8.3", "8.2", "8.1" ] }
}
}
Required parameters
id (numeric, in URL) - hosting account id
version (string) - one of the versions from GET /webhosting/{id}/php, for example "8.3"
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
Returns 400 ("Unsupported PHP version.") if the version is not in the list. If the domain already uses the version, the message is "PHP version unchanged".
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": {
"message": "PHP version changed successfully",
"php": { "current": "8.4", "versions": [ "8.4", "8.3", "8.2", "8.1" ] }
}
}
Parameters
id (numeric, in URL) - hosting account id
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
quota and usage are in MB. A quota or send_limit of 0 means unlimited.
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": {
"emails": [
{
"email": "[email protected]",
"username": "post",
"quota": 0,
"quota_unlimited": true,
"usage": 12.4,
"sent": 3,
"send_limit": 200,
"send_limit_unlimited": false,
"suspended": false
}
]
}
}
Required parameters
id (numeric, in URL) - hosting account id
email (string) - the part before the @
password (string)
Optional parameters
quota (numeric) - mailbox size in MB, 0 (default) means unlimited
domain (string, query) - which domain on the account to create the address on, default the primary domain
Returns status 201.
Required parameters
id (numeric, in URL) - hosting account id
email (string, in URL) - the full email address
password (string)
Required parameters
id (numeric, in URL) - hosting account id
email (string, in URL) - the full email address
quota (numeric) - mailbox size in MB, 0 means unlimited
Parameters
id (numeric, in URL) - hosting account id
email (string, in URL) - the full email address
Parameters
id (numeric, in URL) - hosting account id
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": {
"forwarders": [
{ "user": "sales", "email": "[email protected]", "destinations": [ "[email protected],[email protected]" ] }
]
}
}
Required parameters
id (numeric, in URL) - hosting account id
user (string) - the address to forward (part before the @)
destinations (array or comma-separated string) - where to forward the mail
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
Returns status 201.
Required parameters
id (numeric, in URL) - hosting account id
user (string, in URL) - the forwarding address (part before the @)
destinations (array or comma-separated string) - replaces the current destinations
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
Parameters
id (numeric, in URL) - hosting account id
user (string, in URL) - the forwarding address (part before the @)
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
Parameters
id (numeric, in URL) - hosting account id
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
The setting is returned in the catch_all object: :fail: (reject), :blackhole: (discard) or the email address mail is sent to.
Required parameters
id (numeric, in URL) - hosting account id
catch (string) - :fail: to reject the mail (default), :blackhole: to discard it silently, or address to deliver it to one address
Optional parameters
value (string) - the email address to deliver to. Required when catch is address
domain (string, query) - which domain on the account, default the primary domain
Parameters
id (numeric, in URL) - hosting account id
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": {
"autoresponders": [
{ "user": "post", "email": "[email protected]" }
]
}
}
Parameters
id (numeric, in URL) - hosting account id
user (string, in URL) - the address (part before the @)
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": {
"user": "post",
"email": "[email protected]",
"subject": "Out of office",
"text": "I am away until Monday.",
"cc": "OFF",
"reply_encoding": "UTF-8",
"reply_content_type": "text/plain",
"reply_once_time": "2d"
}
}
Required parameters
id (numeric, in URL) - hosting account id
user (string) - the address (part before the @)
Optional parameters
subject (string) - reply subject, default Autoreply
text (string) - reply message
reply_content_type (string) - text/plain (default) or text/html
reply_once_time (string) - how often the same sender gets a reply: 1h, 2h, 4h, 8h, 12h, 1d, 2d (default), 3d or 7d
cc (string) - OFF (default) or ON
domain (string, query) - which domain on the account, default the primary domain
Returns status 201.
Parameters
id (numeric, in URL) - hosting account id
user (string, in URL) - the address (part before the @)
Accepts the same fields as the create call, including the domain query parameter. Send all fields: any field left out is reset to its default.
Parameters
id (numeric, in URL) - hosting account id
user (string, in URL) - the address (part before the @)
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
Parameters
id (numeric, in URL) - hosting account id
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
When DKIM is enabled, record holds the TXT record to publish in DNS.
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": {
"dkim": {
"available": true,
"enabled": true,
"record": { "name": "x._domainkey", "value": "v=DKIM1; k=rsa; p=MIIBIjANBgkq..." }
}
}
}
Required parameters
id (numeric, in URL) - hosting account id
enable (boolean) - true to enable, false to disable
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
When the domain uses our DNS, the DKIM TXT record is added or removed automatically. The response includes the new status in the dkim object.
Parameters
id (numeric, in URL) - hosting account id
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
The response includes the fields of the update call below.
The spam filter is always switched on by this call. All settings are saved together: send every field, since a field left out is reset to its default.
Optional parameters
where (string) - what to do with spam: inbox (deliver as normal, default), spamfolder, userspamfolder or delete
required_hits (string) - score before a mail counts as spam, default 5.0
high_score_block (string) - yes or no (default), block mail with a very high score
high_score (string) - the score that counts as very high, default 15
rewrite_subject (string) - 1 to add a tag to the subject of spam, 0 (default) to leave it
subject_tag (string) - the tag to add, default *****SPAM*****
report_safe (string) - 0 (default) to keep the original message as it is, 1 or 2 to wrap spam in a report message
blacklist_from (string) - senders always treated as spam, one per line (wildcards such as *@example.com allowed)
whitelist_from (string) - senders never treated as spam, one per line
domain (string, query) - which domain on the account, default the primary domain
Parameters
id (numeric, in URL) - hosting account id
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": [
{ "username": "[email protected]", "path": "/home/exampleno/domains/example.no/public_html/upload" }
]
}
Required parameters
id (numeric, in URL) - hosting account id
username (string)
password (string)
Optional parameters
path (string) - a folder to limit the account to, relative to the domain's website root (public_html). Leave empty to give access to the whole domain folder.
domain (string, query) - which domain on the account, default the primary domain
Returns status 201.
Required parameters
id (numeric, in URL) - hosting account id
ftp_user (string, in URL) - the FTP username, either the full user@domain form from the list or just the name
password (string)
Optional parameters
domain (string, query) - which domain on the account, used when ftp_user has no @domain part. Default the primary domain
Parameters
id (numeric, in URL) - hosting account id
ftp_user (string, in URL) - the FTP username, either the full user@domain form from the list or just the name
Optional parameters
domain (string, query) - which domain on the account, used when ftp_user has no @domain part. Default the primary domain
Databases belong to the account, not to a single domain.
Parameters
id (numeric, in URL) - hosting account id
The response is a databases array where each entry has name and size.
Required parameters
id (numeric, in URL) - hosting account id
name (string) - database name
password (string) - password for the database user
The account username is added in front of the name automatically (for example shop becomes exampleno_shop), and a database user with the same name is created. Returns status 201.
Required parameters
id (numeric, in URL) - hosting account id
dbname (string, in URL) - the full database (user) name, as shown in the list
password (string)
Parameters
id (numeric, in URL) - hosting account id
dbname (string, in URL) - the full database name, as shown in the list
Scheduled commands that run on the account. Each schedule field uses the standard cron syntax (for example *, */5, 0-23 or 1,15) and defaults to *.
Parameters
id (numeric, in URL) - hosting account id
php_bin_path is the full path to the PHP binary, for use in commands.
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": {
"crons": [
{
"id": "000",
"minute": "*/15",
"hour": "*",
"day_of_month": "*",
"month": "*",
"day_of_week": "*",
"command": "/usr/local/bin/php /home/exampleno/domains/example.no/public_html/cron.php"
}
],
"php_bin_path": "/usr/local/bin/php"
}
}
Required parameters
id (numeric, in URL) - hosting account id
command (string) - the command to run. Add >/dev/null 2>&1 at the end to avoid getting an email with the output
Optional parameters
minute (string) - default *
hour (string) - default *
dayofmonth (string) - default *
month (string) - default *
dayofweek (string) - 0-7, where 0 and 7 are Sunday. Default *
reboot (boolean) - true to run the command once each time the server starts instead of on a schedule
Note that these fields are named dayofmonth and dayofweek, while the list returns day_of_month and day_of_week. Returns status 201.
Required parameters
id (numeric, in URL) - hosting account id
cron_id (string, in URL) - the id from the list
command (string)
Accepts the same fields as the create call. The job is replaced as a whole, so fields left out go back to *. The job can get a new id; list the jobs again afterwards.
Parameters
id (numeric, in URL) - hosting account id
cron_id (string, in URL) - the id from the list
Existing subdomains are listed by GET /webhosting/{id}/domains.
Required parameters
id (numeric, in URL) - hosting account id
subdomain (string) - the subdomain name without the domain, for example blog
Optional parameters
domain (string, query) - which domain on the account to add it to, default the primary domain
The subdomain gets its own folder under the domain's public_html. DNS records are not created; point the subdomain to the account yourself. Returns status 201.
{
"meta": { "status": 201, "status_message": "201 Created" },
"data": { "message": "Subdomain created successfully", "subdomain": "blog.example.no" }
}
Parameters
id (numeric, in URL) - hosting account id
name (string, in URL) - the subdomain name (blog) or the full hostname (blog.example.no)
Optional parameters
domain (string, query) - which domain on the account it belongs to, default the primary domain
These endpoints manage the DNS zone the hosting server keeps for a domain. They only take effect if the domain uses the hosting server's name servers. If the domain uses our regular DNS service, manage its records with the /dns endpoints instead.
Parameters
id (numeric, in URL) - hosting account id
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
The domain itself is shown as @. external_dns is true when the hosting server has no DNS zone for the domain.
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": {
"dns": [
{ "id": "1", "name": "@", "type": "A", "value": "203.0.113.10", "ttl": "3600", "priority": null },
{ "id": "2", "name": "@", "type": "MX", "value": "mail.example.no", "ttl": "3600", "priority": "10" }
],
"external_dns": false
}
}
Required parameters
id (numeric, in URL) - hosting account id
type (string) - for example A, AAAA, CNAME, MX or TXT
name (string) - the record name
value (string) - the record value
Optional parameters
ttl (numeric) - default 14400
priority (numeric) - for MX records
domain (string, query) - which domain on the account, default the primary domain
Returns status 201.
Required parameters
id (numeric, in URL) - hosting account id
old_type (string) - type of the current record
old_name (string) - name of the current record
old_value (string) - value of the current record
type (string) - new type
name (string) - new name
value (string) - new value
Optional parameters
ttl (numeric) - default 14400
priority (numeric) - for MX records
domain (string, query) - which domain on the account, default the primary domain
Required parameters
id (numeric, in URL) - hosting account id
type (string) - record type
name (string) - record name
value (string) - record value
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
All paths are relative to the account home directory, so / is the home directory. The website of each domain is in /domains/{domain}/public_html.
Parameters
id (numeric, in URL) - hosting account id
path (string, query) - folder to start from, default /
Parameters
id (numeric, in URL) - hosting account id
path (string, query) - folder to list, default /
page (numeric, query) - page number, default 1
ipp (numeric, query) - items per page, default 50
The entries are returned in the items object.
Parameters
id (numeric, in URL) - hosting account id
path (string, query) - full path to the file
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": { "content": "<?php echo 'Hello'; ?>" }
}
Parameters
id (numeric, in URL) - hosting account id
path (string, query) - full path to the file
The file is returned as a download, not as JSON.
Required parameters
path (string) - the folder
filename (string) - the file name
Optional parameters
text (string) - the file contents. HTML entities such as < are decoded before the file is written
An existing file is overwritten.
Required parameters
path (string) - the folder it is in
old (string) - current name
filename (string) - new name
Required parameters
path (string) - the parent folder
name (string) - folder name
Required parameters
path (string) - the folder
filename (string) - the file name
Required parameters
paths (array) - the full paths to delete
Deleted files are removed permanently, not moved to a trash folder.
Send the request as multipart form data. Existing files with the same name are overwritten.
Required parameters
files[] (file) - the files to upload. Repeat the field to upload several files
Optional parameters
path (string) - target folder, default /
The message tells how many files were uploaded, and how many failed if any did.
Install and manage common web applications with one click, and back them up.
Parameters
id (numeric, in URL) - hosting account id
Applications on all domains are listed. Use id as {installId} in the calls below.
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": [
{
"id": "a1b2c3d4e5f6",
"install_app": "wordpress",
"install_domain": "example.no",
"install_path": "/",
"install_version": "6.8.1",
"install_url": "https://example.no",
"install_created_date": "1767225600",
"install_external_id": "a1b2c3d4e5f6",
"install_title": "My site"
}
]
}
Parameters
id (numeric, in URL) - hosting account id
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": {
"apps": [
{ "id": "wordpress", "name": "WordPress", "category": "Blog", "version": "6.8.1", "description": "...", "popular": true }
]
}
}
Required parameters
id (numeric, in URL) - hosting account id
app (string) - the application id from the available list
Optional parameters
domain (string) - where to install it: any domain on the account or a subdomain of one. Default the primary domain
path (string) - folder to install into, default /
admin_username (string) - default admin
admin_password (string) - generated for you if left out
admin_email (string) - default the account email
site_title (string)
Here the domain is sent in the request body, not as a query parameter. Returns 400 if the domain is not on the account. The installation finishes in the background. Returns status 201 with the admin login.
{
"meta": { "status": 201, "status_message": "201 Created" },
"data": {
"message": "Application installed successfully",
"admin_username": "admin",
"admin_password": "9f2c4e1ab37d8065"
}
}
Parameters
id (numeric, in URL) - hosting account id
installId (string, in URL) - the installation id
Parameters
id (numeric, in URL) - hosting account id
installId (string, in URL) - the installation id
The response is a backups array. Each backup includes id, date, time (Unix timestamp), size_mb, version, type, expiry and filename.
Parameters
id (numeric, in URL) - hosting account id
installId (string, in URL) - the installation id
The hosting account itself is not included; it is always available as location local.
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": {
"locations": [
{ "id": "k3l4m5n6", "type": "SFTP", "label": "[email protected]" }
]
}
}
Required parameters
id (numeric, in URL) - hosting account id
installId (string, in URL) - the installation id
action (string) - backup or restore
When action is backup
location (string, optional) - where to store it: local (default, the hosting account), the id of a saved destination from backuplocations, or new for a new external server
ftp (object, required when location is new):
type (string) - ftp, ftps or sftp
host (string)
port (numeric, optional)
user (string)
pass (string, optional)
path (string, optional)
When action is restore
backup (string) - the backup id to restore
Parameters
id (numeric, in URL) - hosting account id
installId (string, in URL) - the installation id
backupId (string, in URL) - the backup id
The backup is returned as a file download, not as JSON. Returns 404 if the backup does not exist or cannot be downloaded.
Required parameters
id (numeric, in URL) - hosting account id
installId (string, in URL) - the installation id
backup (string) - the backup id to delete
Parameters
id (numeric, in URL) - hosting account id
installId (string, in URL) - the installation id
Each domain on the account has its own certificate.
Parameters
id (numeric, in URL) - hosting account id
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
certificate is null when no certificate is installed. entries lists the hostnames you can include: the domain, www and its subdomains.
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": {
"domain": "example.no",
"enabled": true,
"certificate": {
"common_name": "example.no",
"issuer": "Let's Encrypt",
"valid_from": "2026-09-01 10:00:00",
"valid_to": "2026-11-30 10:00:00",
"is_expired": false,
"sans": [ "example.no", "www.example.no" ],
"serial": "04A1B2C3D4E5F6"
},
"entries": [ "example.no", "www.example.no", "blog.example.no" ]
}
}
Required parameters
id (numeric, in URL) - hosting account id
hostnames (array) - the hostnames to secure: the domain itself and/or hostnames under it
Optional parameters
keysize (string) - secp384r1 (default), secp256r1 or rsa_4096
domain (string, query) - which domain on the account, default the primary domain
The hostnames must point to the hosting account in DNS. Returns 400 if a hostname is not under the domain. The certificate is usually issued within a minute.
Parameters
id (numeric, in URL) - hosting account id
Optional parameters
domain (string, query) - which domain on the account, default the primary domain
These cover the whole hosting account, separate from the per-application backups above.
Parameters
id (numeric, in URL) - hosting account id
{
"meta": { "status": 200, "status_message": "200 OK" },
"data": {
"backups": [
{ "filename": "backup-Sep-30-2026-1.tar.zst", "date": "2026-09-30", "date_display": "Sep 30, 2026" }
]
}
}
Required parameters
id (numeric, in URL) - hosting account id
action (string) - backup or restore
When action is restore
filename (string) - the backup file to restore, as returned by the list (backup-....tar.zst or .tar.gz)
A backup covers every domain on the account, with website files, subdomains, email accounts and mail, forwarders, autoresponders, FTP accounts and databases. Both backup and restore run in the background.
Required parameters
id (numeric, in URL) - hosting account id
filename (string) - the backup file to delete