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_.
- Ein Sandbox-Token nutzt dieselbe URL wie Produktion, sieht aber nur die Sandbox-Mandanten: „Sandbox Reseller“ mit den Kunden
whmcs:1001(Example GmbH) undwhmcs:1002(Muster AG). - Die Zonen liegen auf einem simulierten Backend. Nichts erreicht echte Nameserver.
- Die Veröffentlichung läuft trotzdem durch
pending → pushed → live(innerhalb weniger Sekunden). - Die Daten werden jede Nacht zurückgesetzt. Tokens bleiben dabei erhalten.
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"
- Idempotency-Key (jedes POST/PATCH):
Netzwerkfehler, 429 und 5xx mit demselben Key wiederholen. PawDNS liefert dann die erste Antwort erneut (Header Idempotent-Replayed: true). Derselbe Key mit anderem Body ergibt
422 idempotency_key_reused. Keys werden 24 h aufbewahrt. - ETag / If-Match: das ETag einer Zone oder eines Eintrags bei PATCH/DELETE als If-Match mitsenden. Hat jemand das Objekt zwischenzeitlich geändert, lautet die Antwort
412 precondition_failed. - Fehler:
application/problem+json. Aufcodeverzweigen (stabil), nie auf den Text. title und detail folgen Accept-Language (de oder en). Bei Support-Anfragen request_id angeben (auch im Header X-Request-Id). - Ratenlimits: die Header RateLimit-Limit, RateLimit-Remaining und RateLimit-Reset beachten. Bei 429 Retry-After abwarten.
5. Webhooks: Signatur prüfen
Jede Zustellung trägt PawDns-Signature: t=<unix>,v1=<hex>
mit v1 = hex(HMAC-SHA256(secret, "<t>.<raw body>")).
- In konstanter Zeit vergleichen.
- Zustellungen ablehnen, deren t mehr als 5 Minuten abweicht.
- Jeden der v1-Werte akzeptieren: Während einer Secret-Rotation gibt es 24 h lang zwei.
- Über PawDns-Delivery deduplizieren.
// 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
- Swagger UI: „Authorize“ klicken, das pdns_test_-Token einfügen, den Sandbox-Server beibehalten und bei jeder Operation „Try it out“ nutzen.
- Mock-Server ganz ohne Token:
npx @stoplight/prism-cli mock https://sandbox.pawdns.de/api/docs/openapi.yaml