Dla programistów → Webhooks

Webhooki

NameOcean wysyła podpisane zdarzenie JSON na Państwa punkt końcowy HTTPS, gdy coś wydarzy się na koncie, dzięki czemu Państwa kod może reagować zamiast odpytywać.

Dodaj punkt końcowy

W Panel → Webhooki, przez API lub prosząc swoją AI przez MCP (create_webhook). Wybierz typy zdarzeń, grupy takie jak dns.* lub wszystkie zdarzenia. Odpowiedź zawiera sekret podpisu (whsec_…).

curl
$ curl -X POST https://nameocean.net/api/v1/webhooks \
    -H "Authorization: Bearer $NAMEOCEAN_API_KEY" -H "Content-Type: application/json" \
    -d '{"url": "https://example.com/hooks/nameocean", "events": ["dns.*", "ssl.issued", "domain.expiring"]}'

Adres URL musi używać https na publicznym serwerze. Odpowiedz dowolnym kodem 2xx w ciągu 10 sekund; czasochłonne operacje wykonuj po udzieleniu odpowiedzi.

Co otrzymujesz

POST https://example.com/hooks/nameocean
Content-Type: application/json
X-NameOcean-Event: dns.record.created
X-NameOcean-Delivery: whd_7c1e0f9a2b3d4e5f6a7b8c9d
X-NameOcean-Signature: t=1794300000,v1=5f2b…

{
  "id": "evt_3a9f1c2e4b5d6a7c8e9f0a1b",
  "type": "dns.record.created",
  "created": "2026-11-10T09:20:00+00:00",
  "data": {
    "zone": "example.com",
    "record": {"id": 4211, "type": "A", "hostname": "www", "ip": "203.0.113.10", "ttl": "1h"}
  }
}

Identyfikator zdarzenia pozostaje taki sam przy ponowieniu lub ponownym wysłaniu dostarczenia: używaj go, aby pomijać już obsłużone zdarzenia. Zdarzenia mogą docierać w innej kolejności.

Weryfikacja podpisu

t to czas uniksowy żądania, a v1 to szesnastkowy HMAC-SHA256 z wartości t, kropki i surowej treści, obliczony z użyciem Państwa sekretu jako klucza. Należy go obliczać na surowych bajtach, przed parsowaniem JSON-a, porównywać w czasie stałym i odrzucać znaczniki czasu starsze niż pięć minut.

X-NameOcean-Signature
t=1794300000,v1=hex(HMAC_SHA256(secret, "1794300000." + raw_body))
Python
import hashlib, hmac, time

def verify(secret: str, header: str, body: bytes, tolerance: int = 300) -> bool:
    fields = dict(part.split("=", 1) for part in header.split(","))
    ts = int(fields["t"])
    if abs(time.time() - ts) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{ts}.".encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, fields.get("v1", ""))
Node.js
import crypto from "node:crypto";

export function verify(secret, header, rawBody, tolerance = 300) {
  const fields = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
  const ts = Number(fields.t);
  if (Math.abs(Date.now() / 1000 - ts) > tolerance) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${ts}.`).update(rawBody).digest("hex");
  const got = Buffer.from(fields.v1 || "", "hex");
  return got.length === 32 && crypto.timingSafeEqual(Buffer.from(expected, "hex"), got);
}
Go
func Verify(secret, header string, body []byte) bool {
	var ts int64
	var v1 string
	for _, part := range strings.Split(header, ",") {
		k, v, _ := strings.Cut(part, "=")
		switch k {
		case "t":
			ts, _ = strconv.ParseInt(v, 10, 64)
		case "v1":
			v1 = v
		}
	}
	if d := time.Now().Unix() - ts; d > 300 || d < -300 {
		return false
	}
	mac := hmac.New(sha256.New, []byte(secret))
	fmt.Fprintf(mac, "%d.", ts)
	mac.Write(body)
	return hmac.Equal([]byte(hex.EncodeToString(mac.Sum(nil))), []byte(v1))
}

Ponowienia i wyłączanie

Dostarczenie bez odpowiedzi, z przekroczonym limitem czasu, kodem 5xx, 408 lub 429 jest ponawiane po 1m, 5m, 30m, 2h, 5h, 10h, 10h: 8 prób w ciągu około doby. Każdy inny kod 4xx kończy się błędem od razu. Gdy 5 dostarczeń z rzędu zakończy się ostatecznym błędem, punkt końcowy zostaje wyłączony, a Państwo otrzymują e-mail; można go ponownie włączyć w panelu lub przez PATCH active: true. Każde dostarczenie wraz z kodem statusu i początkiem odpowiedzi jest widoczne w panelu oraz pod GET /api/v1/webhooks/{id}/deliveries, gdzie można je wysłać ponownie.

Zdarzenia

domain.registeredNa Państwa koncie zarejestrowano domenę.
domain.renewedData wygaśnięcia domeny została przesunięta (odnowienie).
domain.expiringDomena wygasa za 30, 7 lub 1 dzień.
domain.expiredDomena wygasła wczoraj.
domain.nameservers.updatedSerwery nazw domeny zostały zmienione.
domain.transfer.startedW rejestrze zgłoszono transfer przychodzący lub wychodzący.
domain.transfer.completedTransfer został zakończony.
domain.transfer.failedTransfer został odrzucony lub anulowany.
dns.zone.createdUtworzono strefę DNS.
dns.zone.deletedUsunięto strefę DNS.
dns.record.createdDodano rekord DNS.
dns.record.updatedZmieniono rekord DNS.
dns.record.deletedUsunięto rekord DNS.
ssl.issuedCertyfikat został wystawiony po raz pierwszy.
ssl.renewedCertyfikat został odnowiony.
ssl.expiringCertyfikat wygasa za 7 dni i nie został jeszcze odnowiony.
email.mailbox.createdDo jednej z Państwa domen pocztowych dodano skrzynkę pocztową.
email.mailbox.deletedUsunięto skrzynkę pocztową wraz z jej wiadomościami.
email.forwarding.enabledWłączono przekierowanie poczty dla domeny.
email.forwarding.disabledWyłączono przekierowanie poczty dla domeny – przez Państwa lub dlatego, że domena przestała spełniać wymagania (powód podano w zdarzeniu).
webhook.testWysyłane po kliknięciu „Wyślij test”; ignoruje filtr zdarzeń punktu końcowego.

data zawiera domenę lub strefę oraz obiekt: rekord (z previous przy aktualizacjach), datę wygaśnięcia, serwery nazw (z previous). Dokładne pola każdego obiektu są takie same jak w REST API.

Przychodzące wiadomości e-mail również mogą być wysyłane na adres URL: ustaw to dla każdego adresu w Przekierowaniu poczty. Te żądania używają tych samych nagłówków i podpisu, z X-NameOcean-Event: email.received.

Warto wiedzieć

  • NameOcean wysyła żądania wyłącznie na adresy publiczne, sprawdzane ponownie przy każdym dostarczeniu, i nigdy nie podąża za przekierowaniami.
  • Jeśli sekret wycieknie, wygeneruj nowy w panelu; zdarzenia są od razu podpisywane nowym sekretem.
  • Wyślij test natychmiast wysyła zdarzenie webhook.test, niezależnie od filtra zdarzeń punktu końcowego.