PawDNS REST APIEinstieg
← API-Referenz (Swagger UI) English · Deutsch

PawDNS REST API v1: Einstieg

Basis-URL: https://sandbox.pawdns.de/api/v1. Der vollständige Vertrag ist die OpenAPI-Spec (auch als JSON).

1. Sandbox-Token besorgen

Ein Sandbox-Token gibt es beim PawHost-Team. Admins legen es in der PawDNS-Verwaltung unter „API sandbox“ an. Sandbox-Tokens beginnen mit pdns_test_.

Produktions-Tokens beginnen mit pdns_live_. Tokens gehören auf den Server und nie in den Browser.

2. Erste Anfragen

export BASE=https://sandbox.pawdns.de/api/v1
export T=pdns_test_…            # Ihr Token

# Wer bin ich? (Mandant, Limits, Funktionen, Scopes)
curl -s -H "Authorization: Bearer $T" -H "Accept-Language: de" "$BASE/me"

# Zonen (Cursor-Paginierung: pagination.next_cursor als ?cursor= übergeben)
curl -s -H "Authorization: Bearer $T" "$BASE/zones?limit=50"

3. Im Namen eines Kunden handeln

Ein Panel-Token (Scope act_as) schickt den Kunden bei jeder Anfrage mit. PawDNS antwortet dann genau so, als hätte der Kunde selbst gefragt: seine Zonen, IPs, Kontingente und Funktionen. Der Header sagt nur, wer handelt. Was dem Kunden gehört, schlägt PawDNS selbst nach.

curl -s -H "Authorization: Bearer $T" -H "X-Act-As-Customer: whmcs:1001" "$BASE/me"
curl -s -H "Authorization: Bearer $T" -H "X-Act-As-Customer: ten_4821"   "$BASE/zones"

Kunden außerhalb des Mandantenbaums Ihres Tokens ergeben 403 act_as_not_allowed, unbekannte ergeben 404 act_as_unknown.

4. Schreiben, Idempotenz und Nebenläufigkeit

curl -s -H "Authorization: Bearer $T" -H "X-Act-As-Customer: whmcs:1001" \
     -H "Content-Type: application/json" -H "Idempotency-Key: $(uuidgen)" \
     -d '{"comment": "neuer Webserver", "changes": [
           {"op": "replace_rrset", "name": "www", "type": "A", "ttl": 3600, "records": [{"address": "192.0.2.20"}]}
         ]}' \
     "$BASE/zones/example.com/changesets"

5. Webhooks: Signatur prüfen

Jede Zustellung trägt PawDns-Signature: t=<unix>,v1=<hex> mit v1 = hex(HMAC-SHA256(secret, "<t>.<raw body>")).

// PHP
function pawdnsVerify(string $rawBody, string $header, string $secret): bool {
    $parts = [];
    foreach (explode(',', $header) as $kv) { [$k, $v] = array_pad(explode('=', trim($kv), 2), 2, ''); $parts[$k][] = $v; }
    $t = (int) ($parts['t'][0] ?? 0);
    if (abs(time() - $t) > 300) return false;
    $expected = hash_hmac('sha256', $t.'.'.$rawBody, $secret);
    foreach ($parts['v1'] ?? [] as $sig) { if (hash_equals($expected, $sig)) return true; }
    return false;
}
// $ok = pawdnsVerify(file_get_contents('php://input'), $_SERVER['HTTP_PAWDNS_SIGNATURE'] ?? '', $secret);
// Node.js
const crypto = require('crypto');
function pawdnsVerify(rawBody, header, secret) {
  const parts = header.split(',').map(s => s.trim().split('='));
  const t = Number((parts.find(([k]) => k === 't') || [])[1]);
  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
  const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
  return parts.filter(([k]) => k === 'v1').some(([, v]) =>
    v.length === expected.length && crypto.timingSafeEqual(Buffer.from(v), Buffer.from(expected)));
}
# Python
import hmac, hashlib, time
def pawdns_verify(raw_body: bytes, header: str, secret: str) -> bool:
    parts = [p.strip().split("=", 1) for p in header.split(",")]
    t = int(next((v for k, v in parts if k == "t"), "0"))
    if abs(time.time() - t) > 300:
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return any(hmac.compare_digest(expected, v) for k, v in parts if k == "v1")

Mit einem beliebigen 2xx innerhalb von 10 s antworten. Fehlgeschlagene Zustellungen werden nach 1 min, 5 min, 30 min, 2 h, 6 h, 12 h und 24 h wiederholt.

6. Weiter