1. Create an API key
Log in to the customer portal under "KernelHost API" and create a key. Choose only the scopes you actually need (default: read-only). The secret is shown only once, store it safely in your secret manager.
2. Store the credentials
Save key and secret as environment variables. Never in code, never in a repository.
# .env or shell profile
export KH_KEY="kh_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
export KH_SECRET="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
3. Send your first request
List the available products. The signature is built over method, path, timestamp, nonce and body hash.
TS=$(date +%s)
NONCE=$(openssl rand -hex 16)
BODY_SHA256=$(printf '' | openssl dgst -sha256 -hex | awk '{print $NF}')
SIG_INPUT=$(printf 'GET\n/v1/products\n%s\n%s\n%s' "$TS" "$NONCE" "$BODY_SHA256")
SIG=$(printf '%s' "$SIG_INPUT" | openssl dgst -sha256 -hmac "$KH_SECRET" -hex | awk '{print $NF}')
curl https://www.kernelhost.com/cp/kernelhost_api/v1/products \
-H "KH-Key: $KH_KEY" \
-H "KH-Timestamp: $TS" \
-H "KH-Nonce: $NONCE" \
-H "KH-Signature: $SIG"
4. Place an order
Important: POST /v1/orders requires an Idempotency-Key and a hostname. If you retry with the same key after a network error, you get the same response back instead of a second order. Configurable options you omit (for example location or operating system) receive the first value offered in the shop.
BODY='{"product_id":42,"billing_cycle":"monthly","hostname":"web01.example.com"}'
IDEM="order-web01-$(date +%Y%m%d)"
BODY_SHA256=$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')
TS=$(date +%s)
NONCE=$(openssl rand -hex 16)
SIG_INPUT=$(printf 'POST\n/v1/orders\n%s\n%s\n%s' "$TS" "$NONCE" "$BODY_SHA256")
SIG=$(printf '%s' "$SIG_INPUT" | openssl dgst -sha256 -hmac "$KH_SECRET" -hex | awk '{print $NF}')
curl -X POST https://www.kernelhost.com/cp/kernelhost_api/v1/orders \
-H "KH-Key: $KH_KEY" \
-H "KH-Timestamp: $TS" \
-H "KH-Nonce: $NONCE" \
-H "KH-Signature: $SIG" \
-H "Idempotency-Key: $IDEM" \
-H "Content-Type: application/json" \
--data "$BODY"
5. Check the status and read the credentials
The order response lists the service_ids. Query GET /v1/services/{id} until status is active and an IP address is set; setup usually takes a few seconds to a few minutes. Then GET /v1/services/{id}/credentials (scope read:credentials) returns hostname, IP addresses, username and password, for example for your Ansible inventory.
kh_get() {
TS=$(date +%s)
NONCE=$(openssl rand -hex 16)
BODY_SHA256=$(printf '' | openssl dgst -sha256 -hex | awk '{print $NF}')
SIG_INPUT=$(printf 'GET\n%s\n%s\n%s\n%s' "$1" "$TS" "$NONCE" "$BODY_SHA256")
SIG=$(printf '%s' "$SIG_INPUT" | openssl dgst -sha256 -hmac "$KH_SECRET" -hex | awk '{print $NF}')
curl -s "https://www.kernelhost.com/cp/kernelhost_api$1" \
-H "KH-Key: $KH_KEY" \
-H "KH-Timestamp: $TS" \
-H "KH-Nonce: $NONCE" \
-H "KH-Signature: $SIG"
}
kh_get /v1/services/1234
kh_get /v1/services/1234/credentials
6. Store a webhook URL (optional)
You can already store an HTTPS URL per key. Event delivery is in preparation; until then, use the status queries from step 5.

